【问题标题】:Instantiating subclass based on read input input基于读取输入输入实例化子类
【发布时间】:2018-12-23 08:18:39
【问题描述】:

我为了能够从另一个项目中读取文件,我正在复制写入代码并根据需要对其进行调整。

我遇到了一个看起来很丑陋的古玩结构,但我不知道是否有其他方法可以处理它。

代码如下所示:

int type = reader.readInt32():
BaseClass p = BaseClass.Instantiate((BaseClassEnum)type);
object.Read(reader);

这段代码看起来不错,确实不错,但是 BaseClass.Instantiate(BaseClassEnum type) 方法还有一些不足之处。

基本上,它是一个巨大的 switch case 语句,根据传递的类型参数实例化基类的子类。

有什么方法可以避免这里的 switch case 吗?我可以创建一个字典,将 BaseClassEnum 映射到某种允许我调用它的构造函数的类引用吗?比如:

Dictionary<int, ???> bindings = new Dictionary<int, ???>(){
    {BaseClassEnum1, SubClass1},
    {BaseClassEnum2, SubClass2}
}

//...

//Assuming SubClass1 has a constructor SubClass1()
BaseClass p = new bindings[BaseClassEnum1]();

//I could even create a new constructor SubClass(BinaryReader reader) and do
BaseCoass p = new bindings[BaseClassEnum1](reader);

最后,代码将如下所示:

BaseClass p = new bindings[(BaseClassEnum)reader.ReadInt32()](reader);

【问题讨论】:

标签: c# inheritance


【解决方案1】:

类/类型工厂(这是您正在创建的)以四种基本方式之一实现。

  1. Switch 语句或等效语句或一系列 if/then/else 语句
  2. 允许将值映射到特定类型的字典或其他结构
  3. 按名称调用的一些变体(在 C# 中表示反射)
  4. 事件订阅(不经常使用)可能会在内部使用其他方法之一。

Switch 语句很丑,当然也有点容易出错,字典也很丑,并且有自己的错误,但更容易测试。反射通常较慢,而事件订阅较慢。

所以,没有灵丹妙药。

您所描述的内容如下:

var binding = new Dictionary<int, Func<BaseClass>>(){{BaseClassEnum1, ()=> new SubClass1()},
                                                   {BaseClassEnum2, ()=>new SubClass2()}};


var p = new bindings[BaseClassEnum1]();

https://dotnetfiddle.net/rWwCjw 的工作示例(变量名称略有不同)。

我应该注意,上面和示例都有些简化,特别是如果这应该涵盖您的应用程序中所有可能的子类,字典应该是它自己的属性/函数,以便您可以测试 (通过反射)您的应用程序中的所有子类都存在于列表中。

【讨论】:

    【解决方案2】:

    如果你改变问号???到Type你可以使用var p = Activator.Createinstance(binding[BaseClassEnum1], reader)

    Activator.Createinstance

    【讨论】:

      猜你喜欢
      • 2017-08-28
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 2021-11-27
      • 2017-05-25
      • 2022-12-22
      相关资源
      最近更新 更多