对已经加载到app域中的文件进行反射,而不是加载每个文件(再次)

时间:2013-12-09 17:05:49

标签: c# reflection appdomain

我正在使用反射来扫描文件夹中的所有程序集,以查找实现某个接口并从某个基类派生的类型。代码如下所示:

foreach (string file in Directory.GetFiles(folder, "*.dll"))
{
    Assembly assembly = Assembly.LoadFile(file);

    Type foundType = (from type in assembly.GetTypes()
                      where type.GetInterfaces().Contains(typeof(TInterface))
                   && type.BaseType.Name.LeftOf('`') == baseClass.Name.LeftOf('`')
                      select type).FirstOrDefault();

    if (foundType == default(Type)) { continue; }

    // Register our type so we don't need to use reflection on subsequent requests.
    DependencyContainer.Register(typeof(TInterface), foundType);

    return CreateInstance<TInterface>(foundType);
}

在代码审查期间,对这段代码提出了两个问题。首先,一旦找到匹配类型,我们就无法快捷循环;如果找到多个匹配类型,我们需要遍历每个文件并抛出异常。这让我想到了真正的问题...

代码审核员想知道是否有更好的方法来加载每个文件。出于性能原因,我们想知道我们是否可以遍历应用域中已加载的文件,而不是为每个文件调用Assembly.LoadFile(file)。我们想过,为什么要加载每个文件?这是一个有效的问题吗?以这种方式加载文件与文件加载到应用程序域的方式相同吗?循环遍历每个文件的有效方法是什么,这样我们就不会浪费处理时间?

注意:Assembly.LoadFile()的文档不太有用:

  

在指定路径上加载程序集文件的内容。

我不确定这是否等同于将文件加载到应用程序域中,或者这是否完全不同。

3 个答案:

答案 0 :(得分:5)

如果您使用LoadFrom而不是LoadFile,则无需担心 - 如果DLL已加载,则不会再次加载 - 请参阅http://msdn.microsoft.com/en-us/library/1009fa28.aspx。但请注意,这是基于程序集标识而不是路径,因此如果您担心可能有两个程序集,每个程序集具有相同的标识但路径不同,则每次都明确加载它们。 / p>

如果您真的想深入研究这个问题,可以使用AppDomain.CurrentDomain.GetAssemblies获取应用程序域中加载的所有程序集,构建字典或某些此类结构并跳过已加载的程序集。但是,正如我所说,在一个典型的场景中使用LoadFrom,这是不必要的。

答案 1 :(得分:1)

我不确切知道Assembly.LoadFile(file)的行为。但是,您始终可以通过AppDomain.CurrentDomain.GetAssemblies()检查每个单独的程序集与已加载的程序集。

答案 2 :(得分:0)

另一种方法是将文件夹添加到私有探测路径,然后使用Assembly.Load(string)加载Load上下文中的程序集。据我所知,这是推荐的方式。查看MSDN博客Suzanne Cook以获取有关装配加载的更多信息和建议。