2017-02-21 65 views
2

Я разрабатываю программу, которая использует плагины. Все плагины - это классы, которые наследуются от интерфейса KrotAPI.IKrotAPI. Интерфейс хранится в файле krotapi.cs, который распространен как для csproj хоста, так и для каждого плагина * .csproj.Как получить доступ к классу с интерфейсом из DLL?

Принимающие загружает плагины, используя этот код

dynamic LoadPlugin(Assembly asm) 
{ 
    foreach (Type type in asm.GetTypes()) 
    { 
    if (type.GetInterface("KrotAPI.IKrotPlugin") != null) 
    { 
     PluginType = type; 
     dynamic inst = Activator.CreateInstance(type); 
     KrotAPI.IKrotPlugin inst2 = inst as KrotAPI.IKrotPlugin; 
     if (inst2 == null) return inst; 
     Console.WriteLine("Link to API is set up."); 
     return inst2; 
    } 
    } 
    throw new Exception("There are no valid plugin(s) in the DLL."); 
} 

В inst2 всегда пустой, и я вынужден использовать медленные и багги динамические вызовы. Как сделать это как inst, но с KrotAPI.IKrotPlugin типа?


Второй вопрос по почти той же теме. Некоторые функции плагинов возвращают результат типа KrotAPI.FindData (это структура, которая хранится в файле krotapi.cs). Но я не могу получить доступ к нему:

dynamic fd = new KrotAPI.FindData(); 
if (NextItemInfo != null) //NextItemInfo is an instance of that struct 
    fd = NextItemInfo; 
listBox1.Items.Add(fd.FileName); 

На последней строке NET Framework выдает это исключение:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException 'System.ValueType' не содержит определения для 'FileName'

однако поле FileName жестко закодировано в структуры и, конечно, не пустой, или

Microsoft.CSharp.RuntimeBinder.RuntimeBinderInternalCompilerException Неожиданное исключение при связывании динамическую операцию

если заменить последнюю строку с KrotAPI.FindData fd2 = (KrotAPI.FindData) fd; listBox1.Items.Add(fd2.FileName);.

WTF?

ответ

1

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

Есть два способа решить эту проблему:

  1. Пусть ваши плагины ссылки на хост-узел для интерфейса IKrotAPI.
  2. Создайте третью сборку только для интерфейсов и типов данных (например, KrotAPI.FindData), которые являются общими для хоста и сервера.

Я лично предпочитаю второй подход. Он позволяет вам обновить хост-узел без аннулирования существующих плагинов. Чтобы использовать обычное соглашение об именах для такого рода сборки, эту третью сборку можно назвать чем-то вроде KrotAPI. Я склонен думать о «API» как о наборе интерфейсов и типов данных, которые кто-то (т. Е. Разработчик плагинов) будет кодовым, но весь фактический исполняемый код в вашем случае будет либо в хосте, либо в плагине.

+0

Спасибо! Какие проблемы могут возникнуть, когда я выбираю первый путь, а некоторые плагины будут старше или новее, чем хост exe?В настоящее время я вижу это лучше, потому что нет необходимости размещать в каталоге каждого плагина файл KrotAPI.dll, и когда в каталоге плагина нет файла Krot.exe, все все еще работает (как я полагаю, плагины используют сборка, которая уже загружена в память). –

+0

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

+0

Вам не потребуется сборка API в каждом каталоге плагина. Если вы используете стандартную AppDomain, вы можете просто заставить приложение-хозяин загружать сборку API перед загрузкой любого из плагинов, а затем каждый плагин будет использовать уже загруженную сборку API. Вы можете принудительно загрузить сборку несколькими способами (обычно я использую пустой статический метод). Если вы изолируете каждый из своих плагинов в отдельном приложении AppDomain, это немного больше, но вы все равно можете использовать все плагины для использования центральной сборки API. –