Я пытаюсь выполнить проверку сборки для типов, реализующих определенный интерфейс, используя код, подобный этому:
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;
}
Моя проблема в том, что я получаю ReflectionTypeLoadException
при вызове asm.GetTypes()
в некоторых случаях, например. если сборка содержит типы, ссылающиеся на сборку, которая в настоящее время недоступна.
В моем случае меня не интересуют типы, которые вызывают проблему. Типы, которые я ищу, не нуждаются в недоступных ассемблерах.
Вопрос: возможно ли каким-то образом пропускать/игнорировать типы, вызывающие исключение, но все же обрабатывать другие типы, содержащиеся в сборке?
Ответ 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 - я не очень увлечен тем, что он есть сам, но это, вероятно, самый короткий код...
Ответ 2
В то время как кажется, что ничего не может быть сделано без получения 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;
}
Ответ 3
Вы считали Assembly.ReflectionOnlyLoad? Учитывая то, что вы пытаетесь сделать, этого может быть достаточно.
Ответ 4
В моем случае та же проблема была вызвана наличием нежелательных сборок в папке приложения. Попробуйте очистить папку Bin и перестроить приложение.