【问题标题】:How to prevent ReflectionTypeLoadException when calling Assembly.GetTypes()调用 Assembly.GetTypes() 时如何防止 ReflectionTypeLoadException
【发布时间】:2011-12-14 21:51:11
【问题描述】:

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

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

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

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

【问题讨论】:

  • 它可能比您正在寻找的内容更多的是重写,但 MEF 为您提供了类似的功能。只需使用 [Export] 标记来标记您的每个类,该标记指定它实现的接口。然后你可以只导入你当时感兴趣的那些接口。
  • @Drew,感谢您的评论。我正在考虑使用 MEF,但想看看是否有其他更便宜的解决方案。
  • 给插件类工厂起一个众所周知的名字,这样你就可以直接使用 Activator.CreateInstance() 是一个简单的解决方法。不过,如果您现在由于程序集解析问题而遇到此异常,那么您以后可能也会遇到。
  • @Hans:我不确定我是否完全理解。我正在扫描的程序集可能包含实现给定接口的任意数量的类型,因此没有一种众所周知的类型。 (还有:我正在扫描多个程序集,而不仅仅是一个)
  • 我有几乎相同的代码,同样的问题。我探索的程序集由AppDomain.CurrentDomain.GetAssemblies() 给出,这适用于我的机器,但不适用于其他机器。为什么我的可执行文件中的某些程序集无论如何都无法读取/加载??

标签: .net reflection plugins .net-assembly


【解决方案1】:

一种相当讨厌的方式是:

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 块中移出 - 我自己并不非常热衷于它,但它可能 最短的代码...

【讨论】:

  • 谢谢,这似乎是一个解决方案(我同意,这似乎不是一个干净的解决方案)。
  • 当您尝试使用异常中公开的类型列表时,此解决方案仍然存在问题。无论类型加载异常的原因是什么,FileNotFound、BadImage 等仍然会在每次访问有问题的类型时抛出。
  • @sweetfa:是的,它非常有限 - 但如果 OP 只需要查找名称,例如,应该没问题。
  • 搞笑,这里引用了这篇文章,挺有意思的:haacked.com/archive/2012/07/23/…
  • @sweetfa 这是我为避免返回类型上的 FileNotFound 异常问题而采取的措施:From t As Type In e.Types Where (t IsNot Nothing) AndAlso (t.TypeInitializer IsNot Nothing) 它似乎工作得很好。
【解决方案2】:

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

【讨论】:

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

虽然在某些时候如果没有收到 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】:

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

    【讨论】:

      【解决方案5】:

      Jon Skeet 的回答很好,但你每次都会遇到这个异常。要解决此问题,请使用以下 sn-p 并在 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);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-21
        • 2017-09-08
        • 1970-01-01
        相关资源
        最近更新 更多