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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7889228/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 15:59:19  来源:igfitidea点击:

How to prevent ReflectionTypeLoadException when calling Assembly.GetTypes()

.netreflectionplugins.net-assembly

提问by M4N

I'm trying to scan an assembly for types implementing a specific interface using code similar to this:

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

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

My problem is, that I get a ReflectionTypeLoadExceptionwhen calling asm.GetTypes()in some cases, e.g. if the assembly contains types referencing an assembly which is currently not available.

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

In my case, I'm not interested in the types which cause the problem. The types I'm searching for do not need the non-available assemblies.

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

The question is: is it possible to somehow skip/ignore the types which cause the exception but still process the other types contained in the assembly?

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

回答by Jon Skeet

One fairly nasty way would be:

一种相当讨厌的方式是:

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

It's definitely annoying to have to do this though. You could use an extension method to make it nicer in the "client" code:

不过,必须这样做肯定很烦人。您可以在“客户端”代码中使用扩展方法使其更好:

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

You may well wish to move the returnstatement out of the catch block - I'm not terribly keen on it being there myself, but it probably isthe shortest code...

您可能希望将return语句移出 catch 块 - 我自己并不是非常热衷于它,但它可能最短的代码......

回答by sweetfa

Whilst it appears that nothing can be done without receiving the ReflectionTypeLoadException at some point, the answers above are limited in that any attempt to utilise the types provided from the exception will still give issue with the original issue that caused the type to fail to load.

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

To overcome this the following code limits the types to those located within the assembly and allows a predicate to further restrict the list of types.

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

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

回答by Seb

Have you considered Assembly.ReflectionOnlyLoad? Considering what you're trying to do, it might be enough.

你考虑过Assembly.ReflectionOnlyLoad吗?考虑到您正在尝试做的事情,这可能就足够了。

回答by Sergey

In my case, the same problem was caused by the presence of unwanted assemblies in the application folder. Try to clear the Bin folder and rebuild the application.

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