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



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

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

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

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

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

一种相当糟糕的方式是:

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块-我自己并不非常热衷于它在那里,但它可能最短的代码…

虽然在某些时候没有收到reflectiontypeloadeexception似乎什么都做不了,但上面的答案是有限的,因为任何利用异常提供的类型的尝试仍然会引起导致类型加载失败的原始问题。

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

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

您考虑过汇编吗?ReflectionOnlyLoad吗?考虑到您要做的事情,这可能已经足够了。

Jon Skeet的答案工作得很好,但是每次您仍然会遇到这个异常。要解决这个问题,请使用下面的代码片段并打开"Just My Code"

[DebuggerNonUserCode]
public static IEnumerable<Type> GetSuccesfullyLoadedTypes(Assembly assembly)
{
    try
    {
        return assembly.GetTypes();
    }
    catch (ReflectionTypeLoadException e)
    {
        // If some types can't be loaded, this exception is thrown.
        // The [DebuggerNonUserCode] makes sure these exceptions are not thrown in the developers
        // face when they have "Just My Code" turned on in their debugging settings.
        return e.Types.Where(t => t != null);
    }
}

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

相关内容

  • 没有找到相关文章

最新更新