Как правильно отливать объекты, созданные с помощью отражения - PullRequest
10 голосов
/ 28 августа 2008

Я пытаюсь обернуть голову вокруг отражения, поэтому я решил добавить возможность плагина в программу, которую я пишу. Единственный способ понять концепцию - это испачкать пальцы и написать код, поэтому я пошел по пути создания простой библиотеки интерфейсов, состоящей из интерфейсов IPlugin и IHost, библиотеки реализации подключаемых модулей классов, реализующих IPlugin, и простого консольный проект, который создает экземпляр класса реализации IHost, который выполняет простую работу с объектами плагина.

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

Я попробовал этот код, но не смог привести объект o так, как ожидал. Я прошел через процесс с отладчиком, и был вызван соответствующий конструктор. Объект Quickwatching 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. Есть ли какая-то важная часть размышления, которую я просто не понимаю?

Ответы [ 7 ]

4 голосов
/ 28 августа 2008

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

Самая простая вещь для выполнения этой работы - это иметь интерфейс IPlugin, помеченный как общедоступный в вашей сборке хоста, а затем иметь вашу сборку подключаемого модуля эталонной сборки хост-приложения , так что обе сборки имеют доступ к тот же интерфейс .

2 голосов
/ 07 октября 2008

хммм ... Если вы используете Assembly.LoadFrom для загрузки вашей сборки, попробуйте изменить ее вместо Assembly.LoadFile.

работал для меня

Отсюда: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx

1 голос
/ 07 октября 2008

Я просто пытался решить это сам и сумел наткнуться на ответ!

У меня было 3 разных проекта на C #

  • A - Проект интерфейса плагина
  • B - Host exe project -> ссылки A
  • C - Проект внедрения плагина -> ссылки A

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

Е.Г.

IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);

не удался, потому что сборка, в которой был определен интерфейс IPluginModule, называлась «Общая», однако тип -типа, который я приводил, был «Blah.Plugins.Common.IPluginModule».

Я изменил имя сборки для интерфейса интерфейса на «Blah.Plugins.Common», что означало, что приведение успешно завершено.

Надеюсь, это объяснение кому-нибудь поможет. Вернуться к коду ..

1 голос
/ 29 августа 2008

@ lubos hasko

Ты прибил его к носу. В моем первоначальном проекте было три разных сборки, причем реализация хоста и плагина ссылалась на сборку интерфейса плагина.

Я попробовал отдельное решение с реализацией хоста и сборкой интерфейса и сборкой реализации плагина. В этом решении код в первом блоке работал как ожидалось.

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

0 голосов
/ 26 января 2011

Ссылка на указанную выше ссылку является основным решением проблемы с использованием Assembly.LoadFile () вместо .LoadFrom ()

0 голосов
/ 28 августа 2008

@ Haacked

Я пытался сделать псевдокод простым. foreach занимают много места и брекетов. Я уточнил это.

o.GetType (). FullName возвращает Plugins.Multiply, который является ожидаемым объектом. Plugins.Multiply реализует IPlugin. Я проходил через процесс в отладчике довольно много раз, пока не сдался на вечер. Не мог понять, почему я не смог его разыграть, потому что я смотрел, как стрелял конструктор, пока не рассердился на весь этот беспорядок Вернулся к нему сегодня вечером и заставил его работать, но я до сих пор не понимаю, почему приведение не удалось в первом блоке кода. Второй блок кода работает, но мне это кажется неприятным.

0 голосов
/ 28 августа 2008

Ваш тип не публичный, если это так, вызовите перегрузку, которая принимает логическое значение:

Activator.CreateInstance(type, true);

Также, в вашем первом примере, посмотрите, является ли o нулевым, а если нет, выведите o.GetType (). Name, чтобы увидеть, что это на самом деле.

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