Как предотвратить ReflectionTypeLoadException при вызове Assembly.GetTypes () - PullRequest
89 голосов
/ 25 октября 2011

Я пытаюсь отсканировать сборку для типов, реализующих определенный интерфейс, используя код, подобный следующему:

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() в некоторых случаях, например если сборка содержит типы, ссылающиеся на сборку, которая в данный момент недоступна.

В моем случае меня не интересуют типы, вызывающие проблему. Типы, которые я ищу, не нуждаются в недоступных сборках.

Вопрос в том, можно ли каким-то образом пропустить / игнорировать типы, которые вызывают исключение, но все же обрабатывают другие типы, содержащиеся в сборке?

Ответы [ 4 ]

118 голосов
/ 25 октября 2011

Один довольно неприятный способ будет:

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 - я сам не очень заинтересован, чтобы он там был, но, вероятно, это самый короткий код ...

22 голосов
/ 16 октября 2012

Хотя кажется, что в какой-то момент ничего нельзя сделать, не получив исключение 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 голосов
/ 03 января 2016

В моем случае такая же проблема была вызвана наличием нежелательных сборок в папке приложения. Попробуйте очистить папку Bin и пересобрать приложение.

3 голосов
/ 25 октября 2011

Рассматривали ли вы Assembly.ReflectionOnlyLoad ? Учитывая то, что вы пытаетесь сделать, этого может быть достаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...