使用MulticastDelegate作为参数,同时避免使用DynamicInvoke

我有一个MulticastDelegate ,可以引用具有相同签名的许多(遗留)代理之一。 例如:

 public delegate void ObjectCreated(object sender, EventArgs args); public delegate void ObjectDeleted(object sender, EventArgs args); //... 

然后,这些代表用于定义事件:

 public event ObjectCreated ObjectWasCreated; public event ObjectDeleted ObjectWasDeleted; 

然后我有一个方法,它接受我用来做一些常见检查的MulticastDelegate

 void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args) { if (handler != null) { // ... handler.DynamicInvoke(sender, args); } } 

这是从定义事件的类的其他方法中调用的:

 DispatchEvent(ObjectWasCreated, sender, args); DispatchEvent(ObjectWasDeleted, sender, args); 

有没有更简洁的方法来避免DynamicInvoke?

这是我的无reflection解决方案。 它基本上将多播委托实现为列表。 更少的代码? 不是。性能更好? 我不知道。 清洁器? 咩。

 public delegate void ObjectCreated(object sender, EventArgs args); public delegate void ObjectDeleted(object sender, EventArgs args); public event ObjectCreated ObjectWasCreated { add { m_ObjectCreatedSubscribers.Add(value.Invoke); } remove { m_ObjectCreatedSubscribers.RemoveAll(e => e.Target.Equals(value)); } } public event ObjectDeleted ObjectWasDeleted { add { m_ObjectDeletedSubscribers.Add(value.Invoke); } remove { m_ObjectDeletedSubscribers.RemoveAll(e => e.Target.Equals(value)); } } private List> m_ObjectCreatedSubscribers = new List>(); private List> m_ObjectDeletedSubscribers = new List>(); void DispatchEvent(List> subscribers, object sender, EventArgs args) { foreach (var subscriber in subscribers) subscriber(sender, args); } 

一个简单的替代方法是使用内置类型,如Action<,>EventHandler而不是自定义委托,以便获得强类型。

 public static event Action ObjectWasCreated; public static event Action ObjectWasDeleted; void DispatchEvent(Action handler, object sender, EventArgs args) { if (handler != null) { // ... handler(sender, args); } } 

要么

 public static event EventHandler ObjectWasCreated; public static event EventHandler ObjectWasDeleted; void DispatchEvent(EventHandler handler, object sender, EventArgs args) { if (handler != null) { // ... handler(sender, args); } } 

现在你的方法调用很简单。

 DispatchEvent(ObjectWasCreated, sender, args); DispatchEvent(ObjectWasDeleted, sender, args); 

但这主要不是一个好的解决方案。

您可以使用dynamic ,仍然比DynamicInvoke更好:

 void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args) { if (handler != null) { // ... ((dynamic)handler)(sender, args); } } 

或者可能是generics:

 void DispatchEvent(T handler, object sender, EventArgs args) { if (handler != null) { // ... ((dynamic)handler)(sender, args); } } 

我做了一个小的性能比较,发现dynamic实际上太好了

百万次尝试

MulticastDelegate + dynamic(第一个例子)=> 40毫秒

generic + dynamic(第二个例子)=> 90 ms

MulticastDelegate + DynamicInvoke(最初给出的问题)=> 940 ms

你可以这样做:

 void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args) { EventHandler eventHandler = (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), handler.GetType().GetMethod("Invoke")); eventHandler(sender, args); } 

但我不确定这是否比使用DynamicInvoke更快。

你必须在某处使用reflection。 如果每个代表都可以保证只有一个订阅者,那么你可以在创建EventHandler时直接使用Delegate.Method属性,但由于它们是事件,它们可能有多个订阅者……