IsAssignableFrom () возвращает false, когда должно возвращать true - PullRequest
17 голосов
/ 06 декабря 2008

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

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

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

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

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

Спасибо

Ответы [ 6 ]

28 голосов
/ 06 декабря 2008

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

Я предлагаю вам напечатать:

typeof (IPlugin).Module.FullyQualifiedName

и

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

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

7 голосов
/ 30 сентября 2015

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

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

Заменить:

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

с:

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

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

6 голосов
/ 12 мая 2016

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

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

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

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

1 голос
/ 14 сентября 2012

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

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

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

        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler([Resolve Function]);
0 голосов
/ 26 октября 2011

Имя метода 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" (и универсальный параметр типа) требует знания во время компиляции. определенных типов.

0 голосов
/ 06 декабря 2008

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

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