Как правильно отбрасывать объекты, созданные с помощью отражения

StackOverflow https://stackoverflow.com/questions/31567

  •  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();

Вот мои вопросы:

  1. Activator.CreateInstance (тип t) возвращает объект, но я не смог привести объект к интерфейсу, реализованному объектом.Почему?
  2. Должен ли я был использовать другую перегрузку CreateInstance()?
  3. Каковы советы и рекомендации, связанные с отражением?
  4. Есть ли какая-то важная часть рефлексии, которую я просто не улавливаю?
Это было полезно?

Решение

Я просто предполагаю здесь, потому что из вашего кода не очевидно, где у вас есть определение интерфейса 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()

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top