You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 23:10:00