Подтвердить что ты не робот

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

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

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

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

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

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

Спасибо

4b9b3361

Ответ 1

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

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

typeof (IPlugin).Module.FullyQualifiedName

и

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

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

Ответ 2

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

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

Заменить:

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

с:

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

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

Ответ 3

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

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

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

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

Ответ 4

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

Ответ 5

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

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

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

        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler([Resolve Function]);

Ответ 6

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