我有一个EventAggregator实现,可以区分事件类型并以该事件类型为参数调用所有已注册的回调,因此Publish-Method如下所示:
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(callback is Action<T>)
仍然返回false,因为T
仍然是IEvent
,并且方法不是Action<IEvent>
,而是Action<SomethingHappenedEvent>
。
所以问题是:如何获得T成为我的SomethingHappenedEvent
?
我可以使用.GetType()在运行时从类中获取实际的Type,所以应该可行吗?我在.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;
}
}