:: Не фоксом единым
C# вызов методов dll через импортированные интерфейсы
_vit
Автор

Сообщений: 5173
Дата регистрации: 29.07.2002
Не могу реализовать вызовы методов dll через импортированные интерфейсы.

Есть некая программа которая работает с оборудованием.
Оборудование выполняет одну и ту же функцию но у разных производителей и моделей имеет разные интерфейсы и протоколы обмена.
Необходимо программу разработать так чтобы она могла без изменений работать со всеми ними.
Для этого для каждой модели оборудования создается своя dll ну типа драйвера которая имеет унифицированный интерфейс с программой
и конвертирует его в интерфейс конкретной модели оборудования.

Реализуется это через рефлексию и позднее связывание.

Сейчас это так

Код dll:

using System;
namespace ClassLibrary
{
public interface IClass
{
void MyMethod(string Arg);
}
public class Class1 : IClass
{
public void MyMethod(string Arg)
{
Console.WriteLine("{0} it's a Class1.", Arg);
}
}
}

Вызов в программе. Используем тип dynamic для экземпляра класса. Все работает:

using System;
using System.Reflection;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string libraryDll;
string className;
libraryDll = @"C:\Users\tn_proju\source\repos\ClassLibrary1\ClassLibrary1\bin\Debug\ClassLibrary1.dll";
className = "ClassLibrary.Class1";
//libraryDll = @"C:\Users\tn_proju\source\repos\ClassLibrary1\ClassLibrary2\bin\Debug\ClassLibrary2.dll";
//className = "ClassLibrary.Class2";
Assembly assm = Assembly.LoadFrom(libraryDll);
Type type = assm.GetType(className);
dynamic instance = assm.CreateInstance(type.FullName);
if (null == instance)
Console.WriteLine("Instantiating Class failed.");
instance.MyMethod(@"Hello "); // Всё работает
}
}
}

Но хочется реализовать вызовы методов dll через интерфейсы С#.
В инете вижу типа работающие примеры но у меня не получается. экземпляр класса пуст.

using System;
using System.Reflection;
using ClassLibrary;
namespace ClassLibrary
{
public interface IClass
{
void MyMethod(string Arg);
}
}
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string libraryDll;
string className;
libraryDll = @"C:\Users\tn_proju\source\repos\ClassLibrary1\ClassLibrary1\bin\Debug\ClassLibrary1.dll";
className = "ClassLibrary.Class1";
//libraryDll = @"C:\Users\tn_proju\source\repos\ClassLibrary1\ClassLibrary2\bin\Debug\ClassLibrary2.dll";
//className = "ClassLibrary.Class2";
Assembly assm = Assembly.LoadFrom(libraryDll);
Type type = assm.GetType(className);
IClass instance = assm.CreateInstance(type.FullName) as IClass;
if (null == instance)
Console.WriteLine("Instantiating Class failed."); // экземпляр класса пуст.
else
instance.MyMethod(@"Hello ");
}
}
}

Изменим строчку

//IClass instance = assm.CreateInstance(type.FullName) as IClass;
IClass instance = (IClass) assm.CreateInstance(type.FullName);

получаем исключение System.InvalidCastException: 'Unable to cast object of type 'ClassLibrary.Class1' to type 'ClassLibrary.IClass'.'


несмотря на то что интерфейсы в dll и вызывающей программе описаны одинаково это оказывается разные интерфейсы.
Ratings: 0 negative/0 positive
Re: C# вызов методов dll через импортированные интерфейсы
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
_vit
несмотря на то что интерфейсы в dll и вызывающей программе описаны одинаково это оказывается разные интерфейсы.
Естественно. А ты ожидал что если они названы одинаково то и будут "одним и тем же" - нет, это тебе не фокс, а строго типизированный язык
Если ты думаешь про систему плагинов, то интерфейс должен быть определён в основной программе - и ровно один раз (это может быть и не сама сборка MyApp, а отдельная сборка с "общими типами" - ну скажем MyApp.Interfaces.dll) а в неопределённом множестве плагинов будут классы этот самый интерфейс реализующие.
При этом есть интересный нюанс - если вдруг тебе потребуется в рантайме выгружать некоторые из ранее загруженных реализаций/плагинов, то в классическом .net framework придётся поприсядать с созданием и уничтожением отдельных AppDomain и междоменными вызовами. т.к. будучи раз загруженной в AppDomain, сборка там останется навсегда. А в .net core смотреть в сторону AssemblyLoadContext где, судя по всему, всё ещё более запущено
Не исключено что проще и надёжнее будет разделить ПО на 2 независимых процесса, "универсальный" и "драйвер конкретного оборудования" с организацией связи между ними либо через IPC либо (если не критично по времени, задержкам и объёму траффика) через банальный HTTP. Если система более массивна (например требуется работа одновременно с несколькими экземплярами оборудования, да ещё и разных моделей) то наверное имеет смысл использовать для общения "менеджера" и набора отдельных "процессов взаимодействия с конкретным устройством" message broker - скажем бесплатный RabbitMQ. Модульность позволит проще организовать и легче разрабатывать, тестировать и внедрять систему.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: C# вызов методов dll через импортированные интерфейсы
_vit
Автор

Сообщений: 5173
Дата регистрации: 29.07.2002
Igor Korolyov
А ты ожидал что если они названы одинаково то и будут "одним и тем же"

Да признаться ожидал но не долго. Очень быстро я понял всю степень своего заблуждения.


Igor Korolyov
то интерфейс должен быть определён в основной программе

Блин, как я сам не допер?
Спасибо тебе Игорь ты настоящий друг!
Теперь все на :bodr:


Igor Korolyov
При этом есть интересный нюанс - если вдруг тебе потребуется в рантайме выгружать некоторые из ранее загруженных реализаций/плагинов,

Про это я в курсе. Если оборудование заменяется то программа закрывается и даже комп выключается так что меня это не затрагивает.
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 17 (Гостей: 17)

© 2000-2024 Fox Club 
Яндекс.Метрика