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

Я пытаюсь осмыслить размышления, поэтому решил добавить в программу, которую пишу, возможность расширения. Единственный способ понять концепцию - запачкать пальцы и написать код, поэтому я пошел по пути создания простой интерфейсной библиотеки, состоящей из интерфейсов 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 (Type t) возвращает объект, но я не мог преобразовать объект в интерфейс, реализованный этим объектом. Почему?
  2. Должен ли я использовать другую перегрузку CreateInstance ()?
  3. Каковы советы и рекомендации, связанные с отражением?
  4. Есть ли какая-то важная часть размышлений, которую я просто не понимаю?
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
0
12 439
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

Activator.CreateInstance(type, true);

Кроме того, в вашем первом примере посмотрите, имеет ли o значение null, а если нет, распечатайте o.GetType (). Name, чтобы увидеть, что это на самом деле.

@ Haacked

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

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

Ответ принят как подходящий

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

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

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

Andrew 07.10.2008 16:57

@ Любоша хаско

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

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

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

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

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

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

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

Например.

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 решил это для меня.

Adam Raney 23.03.2011 19:33

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

Другие вопросы по теме