使用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
要么
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属性,但由于它们是事件,它们可能有多个订阅者……