设计:通过Activator.CreateInstance(...)调用管理程序集

时间:2011-01-11 17:09:55

标签: c# design-patterns reflection

我目前正在考虑优化C#(.NET 3.5)应用程序框架,目前我正在查看使用Activator.CreateInstance通过接口调用汇编方法的部分代码。作为一个例子,我有以下,功能齐全的代码:

private object InvokeAssembly(string assemblyPath, string assemblyType, string data)
{
    Assembly assembly = Assembly.LoadFrom(assemblyPath);
    Type type = assembly.GetType(assemblyType, true, true);
    IMyInterface assemblyInterface = (IMyInterface)Activator.CreateInstance(type);

    return assemblyInterface.DoSomething(data);
}

问题是,这是一个好的设计吗?特别是当考虑到这种特殊方法被称为每分钟100次时,以下singleton-esque模式是否会更好?

改进示例代码,由JaredPar提供

Dictionary<string, IMyInterface> assemblyCache = new Dictionary<string, IMyInterface>();

private object InvokeAssembly(string assemblyPath, string assemblyType, string data)
{
    var cacheKey = assemblyPath + "*" + assemblyType;

    IMyInterface assemblyInterface;

    if (!this.assemblyCache.TryGetValue(cacheKey, out assemblyInterface))
    {
        Assembly assembly = Assembly.LoadFrom(assemblyPath);
        Type type = assembly.GetType(assemblyType, true, true);
        assemblyInterface = (IMyInterface)Activator.CreateInstance(type);
        assemblyCache[cacheKey] = assemblyInterface;
    }

    return assemblyInterface.DoSomething(data);
}

在第二个示例中,界面创建一次并重复使用,而不是每次请求创建/收集一次。

似乎合乎逻辑的是,第二种方法是更好的解决方案,但我很高兴被告知它没有任何区别。

值得一提的是,这种方法只有这种方法才能在程序集上运行

3 个答案:

答案 0 :(得分:2)

第二个解决方案会表现更好,但有一个错误。它缓存了IMyInterface实例,并在方法调用中重用它,而无需检查是否将相同的程序集路径和类型传递给方法。具有不同pathtype值的后续调用将导致使用错误的IMyInterface实例。缓存模式需要注意这一点。

一种方法是使用Dictionary<string, IMyInterface>缓存类型。

Dictionary<string, IMyInterface> _map = new Dictionary<string, IMyInterface>();

private object InvokeAssembly(string assemblyPath, string assemblyType, string data)
{
  var key = assemblyPath + "*" + assemblyType;
  IMyInterface data;
  if (!_map.TryGetValue(key, out data)) {
    Assembly assembly = Assembly.LoadFrom(assemblyPath);
    Type type = assembly.GetType(assemblyType, true, true);
    data = (IMyInterface)Activator.CreateInstance(type);
    _map[key] = data;
  }
  return data;
}

答案 1 :(得分:1)

第二种解决方案肯定会表现得更好。程序集是高速缓存的,因此不需要每次都从磁盘重新加载它,但GetType调用和创建实例仍然存在开销。

答案 2 :(得分:0)

我认为第二个通常是次要的 - 通过缓存以这种方式创建的实例,您冒着由该接口的实现维护的任何状态的风险,以可能无法预测的方式与您的程序的其余部分进行交互。

我认为这是导致性能问题的Activator调用?毕竟,CreateInstance不是书中最快的东西 - 更好的方法是创建和缓存轻量级委托给相关类型的构造函数并调用它们。您可以通过DynamicMethod执行此操作 - 在Google周围寻找有关“工厂反射动态方法”的信息,这样可以获得大量结果,here's one of them