У меня есть реализация EventAggregator, которая различает типы событий и вызывает все зарегистрированные обратные вызовы с этим типом события в качестве параметра, поэтому метод публикации выглядит следующим образом:
public void Publish<T>(T args) where T : IEvent
{
if (callbacks != null)
{
var callbacksByEvent = callbacks.GetCallbacksByEventType(typeof(T));
if (callbacksByEvent != null)
{
foreach (var callback in callbacksByEvent)
{
if (callback is Action<T>)
{
Task.Run(() => ((Action<T>)callback)(args));
}
}
}
}
}
IEvent - это просто пустой маркерИнтерфейс для Классов Событий.Он отлично работает при передаче жестко закодированной реализации, такой как SomethingHappenedEvent : IEvent
, в метод, но я хотел создать окно уведомлений, где любая реализация IEvent может быть назначена кнопкам «Да», «Нет», «Отмена», и они будутвыполняется при нажатии:
private IEvent CancelEvent;
private void Cancel()
{
if (CancelEvent != null)
{
EventAggregator.Publish(CancelEvent);
}
}
В этом сценарии callbacks.GetCallbacksByEventType(typeof(T))
возвращает значение NULL, поскольку T
равно IEvent
, но методы обратного вызова зарегистрированы в реальной реализации: EventAggregator.Subscribe<SomethingHappenedEvent>(OnSomethingHappened)
Если я изменю его на callbacks.GetCallbacksByEventType(args.GetType())
, я получу ожидаемый список обратных вызовов, но оператор if
if(callback is Action<T>)
по-прежнему возвращает false, поскольку T
по-прежнему IEvent
и методэто не Action<IEvent>
, а Action<SomethingHappenedEvent>
.
Итак, вопрос: как мне заставить T стать моим SomethingHappenedEvent
?Я могу получить фактический тип из класса во время выполнения, используя .GetType (), так что это должно быть возможно?Я работаю на .NET Framework 4.5.
Я прочитал кучу сообщений Stackoverflow по универсальным интерфейсам и интерфейсам, но не смог найти то, что искал!Можете ли вы помочь, пожалуйста?Спасибо за чтение всего этого: D
// Редактировать: Извините, вот код для GetCallbacksByEventType
метода:
internal List<Delegate> GetCallbacksByEventType(Type eventType)
{
List<Delegate> callbacks;
lock (delegateTable)
{
if (!delegateTable.ContainsKey(eventType))
{
return null;
}
List<WeakDelegate> weakReferences = delegateTable[eventType];
callbacks = new List<Delegate>(weakReferences.Count);
for (int i = weakReferences.Count - 1; i > -1; --i)
{
WeakDelegate weakReference = weakReferences[i];
if (weakReference.IsAlive)
{
callbacks.Add(weakReference.GetDelegate());
}
else
{
weakReferences.RemoveAt(i);
}
}
if (weakReferences.Count == 0)
{
delegateTable.Remove(eventType);
}
}
return callbacks;
}
и класс WeakReference:
internal sealed class WeakDelegate
{
readonly Type DelegateType;
readonly MethodInfo DelegateFunction;
readonly WeakReference DelegateTarget;
public Delegate GetDelegate()
{
object target = DelegateTarget.Target;
if (target != null)
{
return Delegate.CreateDelegate(DelegateType, target, DelegateFunction);
}
return null;
}
}