Я пытаюсь осмыслить размышления, поэтому решил добавить в программу, которую пишу, возможность расширения. Единственный способ понять концепцию - запачкать пальцы и написать код, поэтому я пошел по пути создания простой интерфейсной библиотеки, состоящей из интерфейсов 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();
Вот мои вопросы:





Ваш тип не является общедоступным, если да, вызовите перегрузку, которая принимает логическое значение:
Activator.CreateInstance(type, true);
Кроме того, в вашем первом примере посмотрите, имеет ли o значение null, а если нет, распечатайте o.GetType (). Name, чтобы увидеть, что это на самом деле.
@ Haacked
Я старался, чтобы псевдокод был простым. foreach занимает много места и занимает много места. Я это уточнил.
o.GetType (). FullName возвращает Plugins.Multiply, который является ожидаемым объектом. Plugins.Multiply реализует IPlugin. Я прошел через этот процесс в отладчике несколько раз, пока не сдался на вечер. Не мог понять, почему я не мог его использовать, потому что я наблюдал за огнем конструктора, пока я не стал сердиться на весь беспорядок. Вернулся к нему сегодня вечером и заставил его работать, но я все еще не понимаю, почему приведение не удалось в первом блоке кода. Второй блок кода работает, но мне он кажется неприятным.
Я просто предполагаю здесь, потому что из вашего кода не очевидно, где у вас есть определение интерфейса IPlugin, но если вы не можете выполнить приведение в своем хост-приложении, тогда у вас, вероятно, есть интерфейс IPlugin в вашей сборке хоста, а затем в то же время в сборка вашего плагина. Это не сработает.
Самый простой способ выполнить эту работу - пометить интерфейс IPlugin как общедоступный в сборке хоста, а затем получить сборку подключаемого модуля сборка эталонного хост-приложения, чтобы обе сборки имели доступ к тот же интерфейс.
Вы прибили его к носу. В моем первоначальном дизайне было три разных сборки, причем реализация как хоста, так и плагина ссылалась на сборку интерфейса плагина.
Я пробовал отдельное решение с реализацией хоста и сборкой интерфейса и сборкой реализации плагина. В этом решении код в первом блоке работал так, как ожидалось.
Вы дали мне немного больше для размышлений, потому что я не совсем понимаю, почему две сборки, ссылающиеся на общую сборку, не получают один и тот же тип из общей сборки.
Я просто пытался сам решить эту проблему и наткнулся на ответ!
У меня было 3 разных проекта на C#
Я также получал ошибку приведения, пока я не изменил имя сборки для моего проекта интерфейса подключаемого модуля, чтобы оно соответствовало пространству имен того, к чему я пытался привести.
Например.
IPluginModule pluginModule = (IPluginModule)Activator.CreateInstance(curType);
произошел сбой, потому что сборка, в которой был определен интерфейс IPluginModule, называлась «Common», однако -type-, к которому я приводил, была «Blah.Plugins.Common.IPluginModule».
Я изменил имя сборки для проекта интерфейса на «Blah.Plugins.Common», что означало, что преобразование завершилось успешно.
Надеюсь, это объяснение кому-то поможет. Вернуться к коду ..
хммм ... Если вы используете Assembly.LoadFrom для загрузки вашей сборки, попробуйте вместо этого изменить Assembly.LoadFile.
Работал на меня
Отсюда: http://www.eggheadcafe.com/community/aspnet/2/10036776/solution-found.aspx
У меня была такая же проблема, как описано здесь. Переход на Assembly.LoadFile решил это для меня.
Ссылка на яйцеголовый выше является основным решением проблемы с использованием Assembly.LoadFile () вместо .LoadFrom ()
Возможно, это небольшой перебор для простого приложения, но альтернативой является создание отдельной библиотеки, которая просто содержит интерфейс и ссылается на него из всего, что нужно о нем знать: o)