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

发布于 2024-10-11 14:54:06 字数 1406 浏览 2 评论 0原文

我目前正在研究优化 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 次,那么下面的单例模式会是更好的设计吗?

改进的示例代码,由 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);
}

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

第二种方法似乎是更好的解决方案,但我很高兴被告知这没有什么区别。

还值得一提的是,这个方法并且只有这个方法对Assembly进行操作

I am currently looking at optimising an C# (.NET 3.5) application framework, and at the moment I am looking at portions of the code that use Activator.CreateInstance to invoke assembly methods via interfaces. As an example I have the following the following, fully functional, code:

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);
}

The question is, is that a good design? Especially when considering that this particular method is called 100's of times a minute, so would the following singleton-esque pattern be a better design?

Improved sample code, courtesy of 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);
}

In this second example the interface is created once and reused rather than created/collected once per request.

It seems logical that the second method is the better solution, however I am more than happy to be told that it makes no difference.

It is also worth mention that this method and only this method operates on the Assembly

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁月蹉跎了容颜 2024-10-18 14:54:06

第二种解决方案性能更好,但有一个错误。它缓存 IMyInterface 实例并在方法调用之间重用它,而无需检查是否将相同的程序集路径和类型传递到方法中。使用不同 pathtype 值的连续调用将导致使用错误的 IMyInterface 实例。缓存模式需要意识到这一点。

实现此目的的一种方法是使用 Dictionary 来缓存类型。

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;
}

The second solution will perform better but has a bug. It cache's the IMyInterface instance and reuses it across method calls without bothering to check that the same assembly path and type were passed into the method. Consequetive calls with different path or type values will cause the wrong IMyInterface instance to be used. The caching pattern needs to be aware of this.

One way to do this is to use a Dictionary<string, IMyInterface> to cache the types.

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;
}
和影子一齐双人舞 2024-10-18 14:54:06

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

The second solution is definitely going to perform better. Assemblies are cached, so it doesn't need to re-load it from disk every time, but there is still overhead involved in the GetType call and creating the instance.

夜无邪 2024-10-18 14:54:06

我认为第二种方法总体上较差——通过缓存以这种方式创建的实例,您将面临由该接口的实现维护的任何状态的风险,以一种潜在不可预测的方式与程序的其余部分进行交互。

我认为是 Activator 调用导致了性能问题?毕竟,CreateInstance 并不是本书中最快的东西——更好的方法是创建和缓存相关类型的构造函数的轻量级委托,然后调用它们。您可以通过 DynamicMethod 来做到这一点——在 Google 上搜索有关“工厂反射动态方法”的信息,这样您会得到很多结果,这是其中之一

I think the second is inferior in general -- by caching the instance created in that fashion, you run the risk of any state maintained by the the implementation of that interface to interact with the rest of your program in a potentially unpredictable way.

It's the Activator calls that are causing you performance issues, I assume? CreateInstance isn't the fastest thing in the book, after all -- a better way to do this is to create and cache lightweight delegates to the constructors of the types in question and invoke those instead. You can do this via DynamicMethod -- poking around Google for information about "factories reflection dynamicmethod" and such will get you a lot of results, here's one of them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文