我正在尝试使用类似于以下的代码扫描程序集以查找实现特定接口的类型:
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
,例如,如果程序集包含引用当前不可用的程序集的类型。
就我而言,我对导致问题的类型不感兴趣。我正在搜索的类型不需要不可用的程序集。
问题是:是否有可能以某种方式跳过/忽略导致异常但仍处理程序集中包含的其他类型的类型?
AppDomain.CurrentDomain.GetAssemblies()
提供,这适用于我的机器,但不适用于其他机器。为什么我的可执行文件中的某些程序集无论如何都无法读取/加载?
一种相当讨厌的方法是:
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 块 - 我自己并不非常热衷于它,但它可能是最短的代码......
虽然在某些时候如果没有收到 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;
}
你考虑过 Assembly.ReflectionOnlyLoad 吗?考虑到您正在尝试做的事情,这可能就足够了。
Assembly.ReflectionOnlyLoad
不能在平台不受支持的 .NET Core 中使用。
就我而言,同样的问题是由应用程序文件夹中存在不需要的程序集引起的。尝试清除 Bin 文件夹并重建应用程序。
Jon Skeet 的回答很好,但是每次你仍然会遇到这个异常。要解决此问题,请使用以下代码段并在 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);
}
}
不定期副业成功案例分享
From t As Type In e.Types Where (t IsNot Nothing) AndAlso (t.TypeInitializer IsNot Nothing)
它似乎工作得很好。