Как правильно отбрасывать объекты, созданные с помощью отражения
-
09-06-2019 - |
Вопрос
Я пытаюсь разобраться в reflection, поэтому решил добавить возможность плагина в программу, которую я пишу.Единственный способ понять концепцию - это испачкать пальцы и написать код, поэтому я пошел по пути создания простой библиотеки интерфейса, состоящей из интерфейсов IPlugin и IHost, библиотеки реализации плагина из классов, реализующих IPlugin, и простого консольного проекта, который создает экземпляр класса реализации IHost, который выполняет простую работу с объектами плагина.
Используя отражение, я хотел перебрать типы, содержащиеся внутри моей библиотеки dll реализации плагина, и создать экземпляры типов.Мне удалось успешно создать экземпляры классов с помощью этого кода, но я не смог привести созданный объект к интерфейсу.
Я попробовал этот код, но мне не удалось привести объект o, как я ожидал.Я прошел через весь процесс с помощью отладчика, и был вызван соответствующий конструктор.Быстрое наблюдение за объектом o показало мне, что у него есть поля и свойства, которые я ожидал увидеть в классе реализации.
loop through assemblies
loop through types in assembly
// Filter out unwanted types
if (!type.IsClass || type.IsNotPublic || type.IsAbstract )
continue;
// This successfully created the right object
object o = Activator.CreateInstance(type);
// This threw an Invalid Cast Exception or returned null for an "as" cast
// even though the object implemented IPlugin
IPlugin i = (IPlugin) o;
Я заставил код работать с этим.
using System.Runtime.Remoting;
ObjectHandle oh = Activator.CreateInstance(assembly.FullName, type.FullName);
// This worked as I intended
IPlugin i = (IPlugin) oh.Unwrap();
i.DoStuff();
Вот мои вопросы:
- Activator.CreateInstance (тип t) возвращает объект, но я не смог привести объект к интерфейсу, реализованному объектом.Почему?
- Должен ли я был использовать другую перегрузку CreateInstance()?
- Каковы советы и рекомендации, связанные с отражением?
- Есть ли какая-то важная часть рефлексии, которую я просто не улавливаю?
Решение
Я просто предполагаю здесь, потому что из вашего кода не очевидно, где у вас есть определение интерфейса IPlugin, но если вы не можете выполнить приведение в своем хост-приложении, то у вас, вероятно, есть интерфейс IPlugin в вашей хост-сборке, а затем одновременно в вашей сборке плагина.Это не сработает.
Самое простое, чтобы заставить это работать, - это пометить интерфейс IPlugin как общедоступный в вашей сборке хоста, а затем создать свою сборку плагина эталонная сборка хост-приложения, таким образом , обе сборки имеют доступ к тот же самый интерфейс.
Другие советы
хммм...Если вы используете Assembly.LoadFrom для загрузки вашей сборки, попробуйте изменить ее Assembly.Вместо этого загрузите файл.
Сработало на меня
Отсюда: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx
Ты попал в самую точку.В моем первоначальном проекте действительно было три разные сборки, причем как хост, так и реализация плагина ссылались на сборку интерфейса плагина.
Я попробовал отдельное решение с реализацией хоста и сборкой интерфейса и сборкой реализации плагина.В рамках этого решения код в первом блоке работал так, как ожидалось.
Вы дали мне еще немного поводов для размышлений, потому что я не совсем понимаю, почему две сборки, ссылающиеся на общую сборку, не получают один и тот же тип из общей сборки.
Я просто пытался разобраться в этом сам и умудрился наткнуться на ответ!
У меня было 3 разных проекта на C #
- Проект интерфейса A - Plugin
- B - Хост-исполняемый проект -> ссылки на A
- Проект реализации C -плагина -> ссылки на A
Я также получал ошибку приведения, пока не изменил имя сборки для моего интерфейса плагина proj, чтобы оно соответствовало пространству имен того, к чему я пытался привести.
Например.
IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);
произошел сбой, потому что сборка, в которой был определен интерфейс IPluginModule, называлась "Common", а -type-, к которому я приводил, был "Бла.Плагины.Обычный.Однако IPluginModule'.
Я изменил название сборки для интерфейса proj на 'Blah.Плагины.Общий" означал, что актерский состав тогда преуспел.
Надеюсь, это объяснение кому-нибудь поможет.Вернемся к коду..
Ваш тип не является общедоступным, если да, вызовите перегрузку, которая принимает логическое значение:
Activator.CreateInstance(type, true);
Кроме того, в вашем первом примере посмотрите, имеет ли значение o значение null, и если нет, распечатайте o.GetType().Name, чтобы увидеть, что это на самом деле.
Я постарался сохранить псевдокод простым.каждый из них занимает много места и имеет фигурные скобки.Я прояснил это.
o.GetType().FullName возвращает плагины.Умножьте, какой объект является ожидаемым.Плагины.Multiply реализует IPlugin.Я несколько раз повторял этот процесс в отладчике, пока не сдался на вечер.Не мог понять, почему я не мог разыграть его, потому что я наблюдал за запуском конструктора, пока не разозлился из-за всего этого беспорядка.Вернулся к этому сегодня вечером и заставил это работать, но я все еще не понимаю, почему приведение не удалось в первом блоке кода.Второй блок кода работает, но мне кажется, что он не работает.
Ссылка на egghead выше является основным решением проблемы использования Assembly.LoadFile() вместо .LoadFrom()