在不调用构造函数的情况下将对象存储在字典中

时间:2017-08-16 15:40:51

标签: c# .net

我目前有一个探测器接口,称为“模型”。在我的工厂类中,我有一个名为CreateDetector的函数,它返回适当的探测器模型。

public Detector CreateDetector(string modelName, string ip, string port) {
    if ( modelName = "A" )
    {
        return new ModelA(ip, port);
    }
    if ( modelName = "B" )
    {
        return new ModelB(ip, port);
    }
    ...
}

对我来说,这似乎效率很低,代码重复多次。在类似的情况下,我通常会使用以下方法。

public Detector CreateDetector(string modelName, string ip, string port) {
    Dictionary<string, Detector> detectors = new Dictionary<string, Detector>()
    {
        { "A", new ModelA(ip, port) },
        { "B", new ModelB(ip, port) },
        ...
    };
        return detectors[modelName]
}

但是,在Detector的当前实现中,基本构造函数始终调用Init(),它尝试连接到设备。显然,我不想将X次连接到设备,因为这可能会导致很多问题。 (这部分让我问这个问题,我理解构造函数不应该很重,但这是遗留代码,不会改变。)

我希望最终结果模拟这样的东西,其中字典只包含对象的声明,但只有在确定您正在使用哪个类时才会调用构造函数。

public Detector CreateDetector(string modelName, string ip, string port) {
    Dictionary<string, Detector> detectors = new Dictionary<string, Detector>()
    {
        { "A", ModelA(ip, port) },
        { "B", ModelB(ip, port) },
        { "C", ModelC(ip, port) },
        ...
        { "X", ModelX(ip, port) },
    };
    if (modelName = "B" || modelName = "C")
    {
       //special case for these 2 models
    }
    return new detectors[modelName]
}

我想要完成的是停止重复的“if / else”,这些都是相同的,但是在我请求它的值之前没有构造函数的初始化。

2 个答案:

答案 0 :(得分:3)

我的班级中会有以下静态字段:

static Dictionary<string, Func<string, string, Detector>> _detectors = new Dictionary<string, Func<string, string, Detector>>()
{
    { "A", (ip, port)=> new ModelA(ip, port) },
    { "B", (ip, port)=> new ModelB(ip, port) }
};

字典的值是对象工厂方法:

var factory = _detectors[modelName];  // returned type is Func<string, string, Detector>
var result = factory(ip, port);

答案 1 :(得分:3)

您似乎正在寻找 Reflection ,如下所示:

using System.Reflection;

...

//DONE: do not recreate the dictionary, but create it once as a static field
static Dictionary<string, Detector> detectors = new Dictionary<string, Detector>() {
  { "A", typeof(ModelA) },
  { "B", typeof(ModelB) },
   ...
};

public Detector CreateDetector(string modelName, string ip, string port) {
  //TODO: validate modelName

  return detectors[modelName]
    .GetConstructor(new Type[] {typeof(string), typeof(string)})
    .Invoke(new object[] {ip, port}) as Detector;
}

如果型号&#39;名称是常规(例如,类名"Model" + modelName)你可以更进一步:删除字典并尝试搜索模型的类型

using System.Linq;
using System.Reflection;

...

public Detector CreateDetector(string modelName, string ip, string port) {
  //TODO: validate modelName

  Type modelType = Assembly
    .GetExecutingAssembly() //TODO: check the assembly
    .GetTypes()
    .Where(t => t.Name == "Model" + modelName)
    .FirstOrDefault();

  if (null == modelType)
    return null; // Not found; you may want to throw exception here

  return modelType
    .GetConstructor(new Type[] {typeof(string), typeof(string)})
    .Invoke(new object[] {ip, port}) as Detector;
}