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

发布于 2024-12-11 12:55:36 字数 655 浏览 0 评论 0原文

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

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在某些情况下,例如,如果程序集包含引用当前不可用的程序集的类型。

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

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

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 ReflectionTypeLoadException when calling asm.GetTypes() in some cases, e.g. if the assembly contains types referencing an assembly which is currently not available.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

宣告ˉ结束 2024-12-18 12:55:36

一种相当令人讨厌的方式是:

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 块 - 我本人不太热衷于它在那里,但它可能是最短的代码......

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 return statement out of the catch block - I'm not terribly keen on it being there myself, but it probably is the shortest code...

泛滥成性 2024-12-18 12:55:36

虽然在某些时候如果不收到 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;
    }

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.

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;
    }
不必在意 2024-12-18 12:55:36

您是否考虑过 Assembly.ReflectionOnlyLoad ?考虑到您想要做什么,这可能就足够了。

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

浮生未歇 2024-12-18 12:55:36

Jon Skeet 的答案很好,但每次你仍然会遇到这个异常。要解决此问题,请使用以下代码片段并在 Visual Studio 的调试设置中打开“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);
    }
}

The answer from Jon Skeet works fine, but you still get this exception thrown in your face every time. To work around that use the following snippet and turn on "Just My Code" in the debugging settings of Visual Studio.

[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);
    }
}
荭秂 2024-12-18 12:55:36

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

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.

白况 2024-12-18 12:55:36

当我的测试项目引用 nuget 包作为“传递依赖项”时,我就发生了这种情况,其版本与我的测试项目不同。我确保两者都安装了相同的软件包版本并且一切正常。

This happened to me when my test project was referencing a nuget package as a "transitive dependency" with a different version than my project-under-test. I ensured both had the same package versions installed and all was well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文