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

M4N*_*M4N 95 .net reflection plugins .net-assembly

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jon*_*eet 125

一个相当讨厌的方式是:

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

尽管如此,这绝对是令人讨厌的.您可以使用扩展方法在"客户端"代码中使其更好:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 当您尝试使用异常中公开的类型列表时,此解决方案仍然存在问题.无论类型加载异常的原因是什么,FileNotFound,BadImage等仍然会抛出对所涉及类型的每次访问. (4认同)
  • 谢谢,这似乎是一个解决方案(我同意,它似乎不是一个干净的解决方案). (2认同)
  • 搞笑,这里引用了这个帖子,挺有意思的:http://haacked.com/archive/2012/07/23/get-all-types-in-an-assembly.aspx/ (2认同)

swe*_*tfa 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;
    }
Run Code Online (Sandbox Code Playgroud)


Seb*_*Seb 5

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

  • 是的,我已经考虑过了。但我没有使用它,否则我将不得不手动加载任何依赖项。此外,代码也无法使用 ReflectionOnlyLoad 执行(请参阅您链接的页面上的备注部分)。 (2认同)
  • `Assembly.ReflectionOnlyLoad` 不能在不支持该平台的 .NET Core 中使用。 (2认同)