IsAssignableFrom() возвращает false, когда он должен возвращать true
Я работаю над плагиновой системой, которая загружает DLL, содержащуюся в указанной папке. Затем я использую рефлексию для загрузки сборок, итерации по типам, которые они содержат, и идентификации любых, которые реализуют мой интерфейс IPlugin
.
Я проверяю это с помощью кода, подобного следующему:
foreach(Type t in myTypes )
{
if( typeof(IPlugin).IsAssignableFrom(t) )
{
...
}
}
По какой-то причине IsAssignableFrom() продолжает возвращать false, когда он должен возвращать true. Я попытался заменить t
, явно передав ему тип, который должен пройти, и он работает нормально, но по какой-то причине он не работает с типами, которые возвращаются из загруженной сборки. Чтобы сделать вещи более странными, код отлично работает на моей совместной машине, но не на моем.
Кто-нибудь знает что-нибудь, что может вызвать подобное поведение?
Спасибо
Ответы
Ответ 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" (и общий параметр типа) требует знания времени компиляции определенных типов.