Вызов реализации производной функции класса из базы - PullRequest
0 голосов
/ 22 февраля 2019

У нас есть следующая ситуация:

public interface IHandle<T> {
 void Handler(T param);
}

public abstract class AbsBase : IWasLeftOutForBrevity {
 public void SomeFunction<T>(T param) {
   // ... see question ...
 }
}

public class Derived : AbsBase, IHandle<int>, IHandle<decimal> {
 public void Handler(int param) {
   // ...
 }
 public void Handler(decimal param) {
   // ...
 }
}

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

У нас есть универсальный контейнер IoC, который внедряет экземпляры IWasLeftOutForBrevity и обычно вызывает SomeFunction в абстрактном базовом классе с заданным типом.SomeFunction предназначен для вызова связанной функции Handler класса Derived как части его операции.

Учитывая, что базовый интерфейс - IWasLeftOutForBrevity, и мы используем его в общей инфраструктуре,у нас нет прямого доступа к Handler методам.

Обычно мы делаем что-то вроде:

GetType().InvokeMember("Handler",
 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
 null,
 this,
 args
);

или аналогичный GetType().GetMethods("Handler", ...) / GetType().GetMethod("Handler", ...), чтобы найти методдля вызова экземпляра.

Дополнительным «осложнением» является то, что тип, используемый в IHandle, часто является реализацией общего интерфейса.

Мне было интересно, есть ли более чистый способдоступа к методам Handler без такого отражения (например, попытка уйти от волшебной строки «Обработчик»), которая более безопасна для типов?

Обновление

У нас нетбыл в состоянии использовать параметры приведения (this is IHandle<T> handle).Существует поток процессов, который использует общий интерфейс верхнего уровня для передачи данных.Затем вызывается AbsBase.SomeFunction с интерфейсом верхнего уровня, и приведение прерывается, потому что производный класс не реализует интерфейс верхнего уровня.

т.е.

public interface IDataAbstraction { }

public class SomeFunctionalHandle : IDataAbstraction { }

public class Derived : AbsBase, IHandle<SomeFunctionalHandle>{
 public void Handler(SomeFunctionalHandle param) {
   // ...
 }
}

// later in a decorator
IWasLeftOutForBrevity instance = getInstance(); // get instance of derived
IDataAbstraction data = getData(); // get data based on IDataAbstraction
instance.SomeFunction(data);

В общей инфраструктуре сервисакод проходит вокруг IDataAbstraction и затем передает его SomeFunction.

1 Ответ

0 голосов
/ 22 февраля 2019

Я бы, наверное, сделал это:

public abstract class AbsBase
{
    public void SomeFunction<T>(T param)
    {
        if (this is IHandle<T> handle)
        {
            handle.Handler(param);
        }
        else
        {
            // Handle error case
        }
    }
}

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

РЕДАКТИРОВАТЬ: Ах, оказывается, @HimBromBeere первым предложил это в комментариях, пока я еще экспериментировал с отражением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...