2011-10-25 39 views
77

我试图扫描组件,用于执行使用类似于此代码的特定接口类型:如何防止ReflectionTypeLoadException调用Assembly.GetTypes()时

public List<Type> FindTypesImplementing<T>(string assemblyPath) 
{ 
    var matchingTypes = new List<Type>(); 
    var asm = Assembly.LoadFrom(assemblyPath); 
    foreach (var t in asm.GetTypes()) 
    { 
     if (typeof(T).IsAssignableFrom(t)) 
      matchingTypes.Add(t); 
    } 
    return matchingTypes; 
} 

我的问题是,我得到一个ReflectionTypeLoadException在某些情况下调用asm.GetTypes()时,例如如果程序集包含引用当前不可用的程序集的类型。

就我而言,我对导致问题的类型不感兴趣。我正在搜索的类型不需要不可用的程序集。

问题是:是否有可能以某种方式跳过/忽略导致异常的类型,但仍处理包含在程序集中的其他类型?

+1

它可能比你想要的重写更多,但MEF为你提供了类似的功能。只需使用指定它实现的接口的[Export]标记标记每个类。然后,您只能导入那些您当时感兴趣的接口。 –

+0

@德鲁,感谢您的评论。我正在考虑使用MEF,但想看看是否有另一种更便宜的解决方案。 – M4N

+0

为插件类工厂提供一个知名的名称,以便您直接使用Activator.CreateInstance()是一种简单的解决方法。尽管如此,如果您现在由于组件解决问题而出现此异常,那么稍后您可能会得到它。 –

回答

101

一个相当讨厌的办法是:

Type[] types; 
try 
{ 
    types = asm.GetTypes(); 
} 
catch (ReflectionTypeLoadException e) 
{ 
    types = e.Types; 
} 
foreach (var t in types.Where(t => t != null)) 
{ 
    ... 
} 

这绝对讨厌不得不这样做虽然。你可以使用一个扩展方法中的“客户”代码,使其更好:

public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) 
{ 
    // TODO: Argument validation 
    try 
    { 
     return assembly.GetTypes(); 
    } 
    catch (ReflectionTypeLoadException e) 
    { 
     return e.Types.Where(t => t != null); 
    } 
} 

您可能希望移动的return声明出来的catch块 - 我不是非常热衷于它在那里,我自己,但它可能是最短的代码...

+2

谢谢,这似乎是一个解决方案(我同意,它似乎并不是一个干净的解决方案)。 – M4N

+3

当您尝试使用异常中公开的类型列表时,此解决方案仍然存在问题。无论类型加载异常的原因是什么,FileNotFound,BadImage等仍然会抛出所有类型的访问权限。 – sweetfa

+0

@sweetfa:是的,它非常有限 - 但如果OP只需要找到名称,例如,它应该没问题。 –

3

你考虑过Assembly.ReflectionOnlyLoad?考虑你想要做什么,这可能就够了。

+1

是的,我已经考虑过了。但我没有使用它,否则我将不得不手动加载任何依赖关系。此外,该代码不能用ReflectionOnlyLoad执行(请参阅您链接的页面上的备注部分)。 – M4N

16

尽管看起来在没有收到ReflectionTypeLoadException的情况下没有任何事情可以做到,但是上面的答案是有限的,因为任何试图利用异常提供的类型的尝试仍然会给导致类型的原始问题无法加载。

为了克服这个问题,以下代码将类型限制为位于程序集内的类型,并允许谓词进一步限制类型列表。

/// <summary> 
    /// Get the types within the assembly that match the predicate. 
    /// <para>for example, to get all types within a namespace</para> 
    /// <para> typeof(SomeClassInAssemblyYouWant).Assembly.GetMatchingTypesInAssembly(item => "MyNamespace".Equals(item.Namespace))</para> 
    /// </summary> 
    /// <param name="assembly">The assembly to search</param> 
    /// <param name="predicate">The predicate query to match against</param> 
    /// <returns>The collection of types within the assembly that match the predicate</returns> 
    public static ICollection<Type> GetMatchingTypesInAssembly(this Assembly assembly, Predicate<Type> predicate) 
    { 
     ICollection<Type> types = new List<Type>(); 
     try 
     { 
      types = assembly.GetTypes().Where(i => i != null && predicate(i) && i.Assembly == assembly).ToList(); 
     } 
     catch (ReflectionTypeLoadException ex) 
     { 
      foreach (Type theType in ex.Types) 
      { 
       try 
       { 
        if (theType != null && predicate(theType) && theType.Assembly == assembly) 
         types.Add(theType); 
       } 
       // This exception list is not exhaustive, modify to suit any reasons 
       // you find for failure to parse a single assembly 
       catch (BadImageFormatException) 
       { 
        // Type not in this assembly - reference to elsewhere ignored 
       } 
      } 
     } 
     return types; 
    } 
1

在我的情况下,同样的问题是由应用程序文件夹中存在不需要的程序集引起的。尝试清除Bin文件夹并重建应用程序。

相关问题