调用Assembly.GetTypes()时如何防止ReflectionTypeLoadException


97

我正在尝试使用类似于以下代码的程序集来扫描实现特定接口的类型的类型:

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]标记标记您的每个类,该标记指定它实现的接口。然后,您只能导入您当时感兴趣的那些接口。
Dirk Dastardly,

@Drew,感谢您的评论。我当时正在考虑使用MEF,但想看看是否还有另一个更便宜的解决方案。
M4N

为插件类工厂提供一个众所周知的名称,以便您可以直接使用Activator.CreateInstance()是一个简单的解决方法。但是,如果由于程序集解析问题而现在得到此异常,那么您稍后可能也会得到它。
汉斯·帕桑

1
@汉斯:我不确定我是否完全理解。我正在扫描的程序集可能包含实现给定接口的许多类型,因此没有一种众所周知的类型。(并且:我正在扫描多个组件,而不仅仅是一个组件)
M4N

2
我几乎有相同的代码,也有相同的问题。我探索的程序集由给出AppDomain.CurrentDomain.GetAssemblies(),这适用于我的机器,但不适用于其他机器。为什么到底为什么我的可执行文件中的某些程序集还是无法读取/加载?
v.oddou

Answers:


130

一种相当讨厌的方式是:

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

4
当您尝试使用异常中公开的类型列表时,此解决方案仍然存在问题。无论类型加载异常的原因是什么,FileNotFound,BadImage等仍将引发对有问题的类型的每次访问。
sweetfa 2012年

@sweetfa:是的,它非常有限-例如,如果OP仅需要查找名称,就可以了。
乔恩·斯基特

1
好笑的是,这个帖子在这里引用,挺有意思:haacked.com/archive/2012/07/23/...
anhoppe

@sweetfa这是我要避免在返回的类型上出现FileNotFound异常的问题:From t As Type In e.Types Where (t IsNot Nothing) AndAlso (t.TypeInitializer IsNot Nothing)看来效果很好。
ElektroStudios

22

尽管在某些时候似乎没有收到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;
    }

4

您是否考虑过Assembly.ReflectionOnlyLoad?考虑您要尝试执行的操作,可能就足够了。


2
是的,我已经考虑过了。但是我没有使用它,因为否则我将不得不手动加载任何依赖项。同样,该代码也不能通过ReflectionOnlyLoad执行(请参见链接页面上的“备注”部分)。
M4N

3

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.