根据读取的输入实例化子类

时间:2018-12-22 11:51:58

标签: c# inheritance

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

我找到了一个看起来很难看的古玩构造,但是我不知道是否还有其他方法可以处理它。

代码看起来像这样:

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

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

基本上,这是一个巨大的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);

2 个答案:

答案 0 :(得分:2)

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

  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的工作示例(变量名略有不同)。

我应该注意,上面的示例都得到了简化,特别是如果假设它涵盖了应用程序中所有可能的子类,则字典应该是其自己的属性/函数,以便您可以测试(通过反射)列表中显示了应用程序中的所有子类。

答案 1 :(得分:1)

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

Activator.Createinstance