Как привести экземпляр реализации к интерфейсу без указания универсального аргумента (реализация знает об этом)?

У меня есть интерфейс:

public interface IA<T>
{
     T fce1(float[] data);
     byte[] fce2(T arg);        
}

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

public class A : IA<float>
{
   public float fce1(float[] data)
   {
       return 1f;//data processing
   }

   public byte[] fce2(float arg)
   {
       return BitConverter.GetBytes(arg);//some kind of serialization
   }        
}

Класс A находится в .dll, и я хочу получить его и вызвать fce2 (fce1()) (поэтому не должно быть неизвестного аргумента или типа. Я хочу сделать что-то следующее:

var data = File.ReadAllBytes("a.dll") 
var assembly = Assembly.Load(data);
var expTypes = assembly.GetExportedTypes();

foreach (var d in assembly.GetExportedTypes())
{
     var obj = Activator.CreateInstance(d);
     if (obj is IA)
     {
          var kernel = obj as IA;
          kernel.fce2(fce1());
     }
}

Цель состоит в том, чтобы запустить fce1 как одну задачу позже, а fce2 как вторую задачу, когда fce1 предоставит результат (это упрощенная ситуация).

Я пробовал это с .NET 4.7

Я знаю, что это можно сделать, чтобы вернуть объект из fce1, а затем привести внутри fce2 объект к нужному типу и обработать его? Но единственный ли это способ? Я хочу избежать кастинга.


person Pavel Kudrna    schedule 18.09.2019    source источник
comment
Я хочу избежать кастинга - Почему? В любом случае, вы можете легко добиться этого с помощью Reflection, что позволит вам динамически вызывать метод, не зная явно тип во время компиляции.   -  person Martin    schedule 18.09.2019
comment
Вызывается ли fc1() для того же объекта, что и fc2()? fce2(fce1(float[])) возвращает byte[]. Это не общее. Напишите неуниверсальный базовый интерфейс с помощью метода byte[] fc2fc1(float[]). Приведите новый экземпляр к этому. Или вы имели в виду, что T fce1(float[] data); будет T fce1(T[] data);?   -  person 15ee8f99-57ff-4f92-890c-b56153    schedule 18.09.2019
comment
@Martin Я также нашел способ использовать динамический тип, это тоже способ. Но производительность низкая как для Reflection, так и для Dynamic.   -  person Pavel Kudrna    schedule 18.09.2019
comment
@EdPlunkett причина, по которой я хочу, чтобы оба метода были разделены на две части, заключается в балансировке нагрузки на ЦП. Представьте, что входной массив float[] в fce1, например. 6M длины, и он поступает каждую секунду ... fce1 должен обрабатывать данные, а fce2 сериализовать результаты. Сериализация может быть выполнена независимо, но следующий пакет float[] может быть обработан только после обработки предыдущего (поскольку входящие данные float[] — это всего лишь фрагмент непрерывного временного ряда)...   -  person Pavel Kudrna    schedule 18.09.2019


Ответы (1)


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

float[] testingPacket = new float[6250000];
dynamic instance = null;

foreach (var d in assembly.GetExportedTypes())
{
    instance = Activator.CreateInstance(d);
}
int L = 0;
for (int i = 0; i < L; ++i)
{
    dynamic result1 = instance.fce1(testingPacket);
    byte[] buffer = instance.fce2(result1) as byte[];
}

Чем выше L, тем период продолжительности цикла for ближе к длительности приведения объекта и использования прямого объявления в качестве IA. Спасибо.

person Pavel Kudrna    schedule 18.09.2019