.NET 3.5下高效实例化20+构造器一致的Animal子类方案咨询
问题背景
现有代码结构
接口 IAnimal
public interface IAnimal { uint NrOfLimbs {get; set;} string PackName {get; set;} //Enum of all currently possible types eAnimalType Type {get;} }
抽象类 Animal(实现IAnimal)
public abstract class Animal : IAnimal { uint NrOfLimbs {get; set;} string PackName {get; set;} eAnimalType Type {get;} internal Animal(uint nrOfLimbs, string packName, eAnimalType type) { NrOfLimbs = nrOfLimbs; PackName = packName; Type = type; } internal Animal(string packName, XmlReader xr) { //Error/null checking should be here but skipping for question brevity. nrOfLimbs = xr.GetAttribute("nrOfLimbs"); Type = xr.GetAttribute("type"); } //Other base/abstract methods etc. }
子类示例(如Monkey)
public class Monkey: Animal { public bool hasTail = false; internal Monkey(uint nrOfLimbs, string packName, eAnimalType type) : base(nrOfLimbs, packName, type) { } internal Monkey(string packName, XmlReader xr) : base(packName, xr) { hasTail = xr.GetAttribute("hasTail"); } //Other potential methods etc. }
需要实现的AnimalFactory类
internal static class AnimalFactory { public static Animal Create(uint nrOfLimbs, string packName, eAnimalType type) { } public static Animal Create(string packName, XmlReader xr) { } }
问题描述
现有20+个类似Monkey的Animal子类,每个都包含参数完全一致的两个构造器,且这些子类已公开在用无法重构。尝试过switch-case(重复代码过多)、反射(性能不佳)、抽象工厂(仍需switch),均不理想。请问在.NET 3.5环境下,是否存在高效且无重复代码的实例化方案?
解决方案
可以采用预编译委托字典的方案,既避免重复代码,又能保证接近直接实例化的性能,具体实现步骤如下:
1. 定义构造器委托类型
先为两种构造器分别定义对应的委托,减少反射的重复调用:
// 对应第一个构造器的委托 internal delegate Animal AnimalCtor(uint nrOfLimbs, string packName, eAnimalType type); // 对应第二个构造器的委托 internal delegate Animal AnimalXmlCtor(string packName, XmlReader xr);
2. 预加载构造器委托到字典
在AnimalFactory中定义两个静态字典,在类初始化时一次性扫描所有Animal子类并缓存对应的构造器委托,后续创建实例时直接从字典取委托调用即可:
internal static class AnimalFactory { private static readonly Dictionary<eAnimalType, AnimalCtor> _ctorMap = new Dictionary<eAnimalType, AnimalCtor>(); private static readonly Dictionary<eAnimalType, AnimalXmlCtor> _xmlCtorMap = new Dictionary<eAnimalType, AnimalXmlCtor>(); // 静态构造器,一次性加载所有构造器委托 static AnimalFactory() { // 获取所有继承自Animal的非抽象子类 var animalTypes = typeof(Animal).Assembly.GetTypes() .Where(t => t.IsSubclassOf(typeof(Animal)) && !t.IsAbstract); foreach (var type in animalTypes) { // 绑定第一个构造器(uint, string, eAnimalType) var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(uint), typeof(string), typeof(eAnimalType) }, null); if (ctor != null) { var animalCtor = (AnimalCtor)Delegate.CreateDelegate(typeof(AnimalCtor), ctor); // 通过自定义特性获取子类对应的枚举类型 var attr = type.GetCustomAttributes(typeof(AnimalTypeAttribute), false).FirstOrDefault() as AnimalTypeAttribute; if (attr != null) { _ctorMap[attr.Type] = animalCtor; } } // 绑定第二个构造器(string, XmlReader) var xmlCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(string), typeof(XmlReader) }, null); if (xmlCtor != null) { var animalXmlCtor = (AnimalXmlCtor)Delegate.CreateDelegate(typeof(AnimalXmlCtor), xmlCtor); var attr = type.GetCustomAttributes(typeof(AnimalTypeAttribute), false).FirstOrDefault() as AnimalTypeAttribute; if (attr != null) { _xmlCtorMap[attr.Type] = animalXmlCtor; } } } } // 辅助特性:标记子类对应的eAnimalType [AttributeUsage(AttributeTargets.Class, Inherited = false)] internal class AnimalTypeAttribute : Attribute { public eAnimalType Type { get; } public AnimalTypeAttribute(eAnimalType type) { Type = type; } } }
3. 为子类添加特性标记
给每个Animal子类添加[AnimalType]特性,明确其对应的枚举类型:
[AnimalFactory.AnimalType(eAnimalType.Monkey)] public class Monkey: Animal { // 原有代码不变 }
4. 实现Create方法
现在Create方法就可以直接通过字典获取委托并调用,完全不需要switch:
public static Animal Create(uint nrOfLimbs, string packName, eAnimalType type) { if (_ctorMap.TryGetValue(type, out var ctor)) { return ctor(nrOfLimbs, packName, type); } throw new ArgumentOutOfRangeException(nameof(type), "不支持的动物类型"); } public static Animal Create(string packName, XmlReader xr) { // 先从XmlReader中读取type枚举值 var typeStr = xr.GetAttribute("type"); if (!Enum.TryParse(typeStr, out eAnimalType type)) { throw new InvalidOperationException("无效的动物类型"); } if (_xmlCtorMap.TryGetValue(type, out var ctor)) { return ctor(packName, xr); } throw new ArgumentOutOfRangeException(nameof(type), "不支持的动物类型"); }
方案优势
- 性能接近直接实例化:静态构造器仅在工厂类首次使用时执行一次反射,后续调用都是直接调用委托,性能和直接
new几乎无差别,远优于每次实例化都用反射。 - 无重复代码:不需要维护冗长的
switch分支,新增子类时只需添加特性标记,工厂代码无需修改。 - 符合开闭原则:后续新增
Animal子类时,只需给子类加特性,无需修改工厂类的代码。
内容的提问来源于stack exchange,提问作者B3h01d3R
相关产品推荐
相关产品推荐

