С# - Как преобразовать из унаследованного типа в тип времени выполнения

85
10

У меня возникают проблемы с обработкой правильного типа во время выполнения.

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

Все обработчики наследуют от моего интерфейса:

public interface IAbstractHandler < in T>  
{
void Handle(T evnt);
}

Пример:

public class SpecificEventHandler: IAbstractHandler< SpecificEvent>
{
public void Handle(SpecificEvent evnt) {
....
}
}

TEvent.cs:

public class TEvent
{
}

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

Вот какой код:

List<TEvent> eventItems = new List<TEvent>();
....
foreach (var evt in eventItems) {
...
dynamic eventHandler = ResolveEventHandler(evt.GetType().Name);
if (evt is MySubtypeEvent subEvent) {
eventHandler.Handle(subEvent); // <-- this works, but I don't want this.
}
eventHandler.Handle(evt); // <-- And this fails, because 'evt' is seemingly
// a TEvent even though it of the correct subclass.
}

То, что я ищу, - это способ сделать "evt" не ТЕЛЕВИДОМ, а реальным типом, но без жесткого кодирования это сделает мой метод eventHandler.Handle() "(я бы предположил).

спросил(а) 2021-01-14T01:20:34+03:00 1 неделя назад
1
Решение
60

Есть много дорог, которые ведут в Рим, и есть несколько способов решить вашу проблему. Один простой подход - использовать общий абстрактный базовый класс для конкретных типов обработчиков событий, который может обеспечить метод Handle(TEvent evt).

public abstract class HandlerBase<T> where T : TEvent, new()
{
public abstract void Handle(T evt);

public void Handle(TEvent evt)
{
if (!(evt is T))
{
throw new ArgumentException("This handler does not support the event type " + evt.GetType().FullName);
}

Handle((T) evt);
}
}

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

public class SpecificEventHandler: HandlerBase<SpecificEvent>
{
public override void Handle(SpecificEvent evnt)
{
....
}
}


Тогда код из вашего вопроса можно упростить, например:

foreach (var evt in eventItems)
{
...
dynamic eventHandler = ResolveEventHandler(evt.GetType().Name);
eventHandler.Handle(evt);
}


Кроме того, чтобы запретить спецификацию обработчика событий с TEvent как параметром родового типа, объявите TEvent как абстрактный класс или превратите его в интерфейс (обратите внимание на ограничение new() я использовал для HandlerBase выше, что позволяет разрешать только конкретные, используется как параметр типового типа). Использование самого TEvent качестве типичного параметра типа для класса HandlerBase i, показанного выше, приведет к двум методам Handle с одной и той же сигнатурой, что приведет к ошибке компиляции.

ответил(а) 2021-01-14T01:20:34+03:00 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема