我有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?
答案 0 :(得分:2)
这是我的无反射解决方案。它基本上将多播委托实现为列表。更少的代码?不是。性能更好?我不知道。清洁器? MEH。
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<Action<object, EventArgs>> m_ObjectCreatedSubscribers = new List<Action<object, EventArgs>>();
private List<Action<object, EventArgs>> m_ObjectDeletedSubscribers = new List<Action<object, EventArgs>>();
void DispatchEvent(List<Action<object, EventArgs>> subscribers, object sender, EventArgs args)
{
foreach (var subscriber in subscribers)
subscriber(sender, args);
}
答案 1 :(得分:1)
一个简单的替代方法是使用内置类型,例如Action<,>
或EventHandler
,而不是自定义委托,以便获得强大的类型。
public static event Action<object, EventArgs> ObjectWasCreated;
public static event Action<object, EventArgs> ObjectWasDeleted;
void DispatchEvent(Action<object, EventArgs> 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);
}
}
或者可能是泛型:
void DispatchEvent<T>(T handler, object sender, EventArgs args)
{
if (handler != null)
{
// ...
((dynamic)handler)(sender, args);
}
}
我做了一个小的效果比较,发现dynamic
实际上太好了:
对于百万次尝试
MulticastDelegate + dynamic(第一个例子)=&gt; 40毫秒
generic + dynamic(第二个例子)=&gt; 90毫秒
MulticastDelegate + DynamicInvoke(最初给出的问题)=&gt; 940毫秒
答案 2 :(得分:0)
您可以执行以下操作:
void DispatchEvent(MulticastDelegate handler, object sender, EventArgs args)
{
EventHandler eventHandler =
(EventHandler)Delegate.CreateDelegate(typeof(EventHandler), handler.GetType().GetMethod("Invoke"));
eventHandler(sender, args);
}
我不确定这是否比使用DynamicInvoke更快。
你必须在某处使用反射。如果每个代表都可以保证只有一个订阅者,那么您可以在创建EventHandler
时直接使用Delegate.Method属性,但由于它们是事件,因此它们可能有多个订阅者...