IsAssignableFrom() возвращает false, когда должно возвращать true

Я работаю над системой плагинов, которая загружает .dll, содержащиеся в указанной папке. Затем я использую отражение для загрузки сборок, перебора содержащихся в них типов и определения тех, которые реализуют мой интерфейс IPlugin.

Я проверяю это с помощью кода, подобного следующему:

foreach(Type t in myTypes )
{
    if( typeof(IPlugin).IsAssignableFrom(t) )
    {
       ...
    }
}

По какой-то причине IsAssignableFrom() продолжает возвращать false, когда он должен возвращать true. Я попытался заменить t, явно указав тип, который должен пройти, и он работает нормально, но по какой-то причине он не работает с типами, которые возвращаются из загруженной сборки. Что еще более странно, код отлично работает на машине моего коллеги, но не на моей.

Кто-нибудь знает что-нибудь, что может вызвать такое поведение?

Спасибо


person bingles    schedule 05.12.2008    source источник


Ответы (7)


Обычно это происходит, когда существует несоответствие между сборкой, содержащей тип IPlugin, на который ссылается текущая сборка, и сборкой, на которую ссылается сборка, содержащая типы, которые вы повторяете.

Предлагаю распечатать:

typeof (IPlugin).Module.FullyQualifiedName

и

foreach (var type in t.GetInterfaces ()) 
{    
    Console.WriteLine (type.Module.FullyQualifiedName)
}

Чтобы увидеть, где несоответствие.

person Jb Evain    schedule 05.12.2008
comment
В моем случае сравнение типов не удается только в случае одного интерфейса, и оно работает хорошо для всех других интерфейсов, определенных в той же сборке! Почему это произошло? Сборка, содержащая интерфейс, копируется в папку bin\debug приложения с помощью пост-сборочного события проекта. Поэтому я думаю, что сборка, на которую ссылается мой стартовый проект (используя прямую ссылку на проект), такая же, как и сборка, скопированная в папку bin\debug приложения. Разве это не так? - person Learner; 20.12.2013
comment
Это было для меня. Мой модуль ссылался на версию 2.0.0.0 сборки, содержащей тип, который я проверял, в то время как реализующий тип реализовывал тип с тем же именем из версии 2.1.0.0 этой сборки. - person James Wiseman; 27.07.2016
comment
Мне кажется, что это не удается, если сборки загружаются в контекст только для отражения. Несмотря на то, что оба типа имеют одно и то же AssemblyQualifiedName. - person Nicholas Miller; 27.10.2016

У меня была такая же проблема, когда интерфейс был определен в отдельной сборке для типа реализации. Итерация и загрузка сборок из корневой папки, содержащей dll с классами и dll с интерфейсом, приводила к несоответствию типов, как указано выше.

Одним из решений было изменить LoadFrom() на LoadFile(). Метод LoadFrom имеет некоторые недостатки, и это один из них:

Если сборка с тем же идентификатором уже загружена, LoadFrom возвращает загруженную сборку, даже если был указан другой путь.

Другой способ преодолеть это — поместить все dll с типами, реализующими интерфейс, в отдельную папку и не копировать сборку, на которую ссылаются (CopyLocal = False), чтобы Assembly.LoadFrom не загружал dll, содержащую интерфейс, в память.

person elm    schedule 12.05.2016
comment
Я столкнулся с точно такой же ситуацией, и это помогло мне. - person Larry; 04.07.2017
comment
У меня была прямо противоположная проблема: я использовал LoadFile вместо LoadFrom, но в любом случае спасибо за указание в правильном направлении! - person Mitch; 07.09.2019
comment
У меня была эта проблема, и CopyLocal спас меня! Спасибо - person zaffaste; 28.09.2020

В некоторых других ответах упоминается отсутствие ясности в названии метода IsAssignableFrom. Я согласен, и в результате использовал его неправильно.

Попробуйте немного поэкспериментировать с перестановкой объектов в своем коде и посмотрите, работает ли это. Например:

Заменять:

if (typeof(IPlugin).IsAssignableFrom(t))

с участием:

if (t.IsAssignableFrom(typeof(IPlugin)))

Сделав это, я не только заставил его работать, но и начал понимать, что на самом деле делает этот метод.

person kad81    schedule 30.09.2015
comment
На самом деле это звучит неправильно. Согласно документации (msdn. microsoft.com/pl-pl/library/) true возвращается, когда текущий экземпляр является интерфейсом, который реализует c. Это делает i.IsAssignableFrom(t) действительным в этом сценарии. - person Wiktor Zychla; 25.04.2016

Иногда проблема заключается в том, что динамическая сборка ссылается на другую сборку.

Одна простая вещь, чтобы отключить локальную копию в сборке (в Visual Studio щелкните ссылку правой кнопкой мыши и установите для локальной копии значение false). Это должно упростить определение каталога, в котором находится сборка.

Вы также можете реализовать преобразователь сборки на тот случай, если .NET не знает, как инициализировать тип.

        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler([Resolve Function]);
person Community    schedule 14.09.2012

Я работаю на Java, который имеет тот же метод API, и я просто не могу понять его при чтении кода (по какой-то причине); поэтому я всегда читаю это в обратном порядке, поскольку в вашем случае «t присваивается IPlugin». Поэтому, если в C# есть «is», как предлагает Джонатон, я всегда буду использовать его — при отражении в Java «instanceof» не работает для Объекты класса, только экземпляры объекта.

person Lawrence Dol    schedule 05.12.2008

Если вы используете .net core и следуете руководству по эта ссылка, то не забудьте добавить ее в свой проект плагина.

<ItemGroup>
    <ProjectReference Include="..\PluginBase\PluginBase.csproj">
        <Private>false</Private>
        <ExcludeAssets>runtime</ExcludeAssets>
    </ProjectReference>
</ItemGroup>

как описано в ссылке. Вы получите вышеуказанную ошибку, если вы этого не сделаете. Мне это тоже помогло

person Bryida    schedule 02.12.2020

Имя метода Type.IsAssignableFrom расплывчато и сбивает с толку, если его применять для тестирования наследования или обнаружения реализаций интерфейса. Следующая оболочка для этих целей будет иметь гораздо больше смысла:

    public static bool CanBeTreatedAsType(this Type CurrentType, Type TypeToCompareWith)
    {
        // Always return false if either Type is null
        if (CurrentType == null || TypeToCompareWith == null)
            return false;

        // Return the result of the assignability test
        return TypeToCompareWith.IsAssignableFrom(CurrentType);
    }

Затем можно получить более понятный код приложения, например:

    bool CanBeTreatedAs = typeof(SimpleChildClass).CanBeTreatedAsType(typeof(SimpleClass));
    CanBeTreatedAs = typeof(SimpleClass).CanBeTreatedAsType(typeof(IDisposable));

Преимущество этого метода по сравнению с ключевым словом «is» заключается в том, что его можно использовать во время выполнения для проверки неизвестных произвольных типов, тогда как ключевое слово «is» (и общий параметр типа) требует знания определенных типов во время компиляции. .

person Mark Jones    schedule 26.10.2011