3

我有一个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?

4

3 回答 3

2

这是我的无反射解决方案。它基本上实现了一个多播委托作为一个列表。代码少?不。更好的性能?我不知道。清洁器?嗯。

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);
}
于 2011-01-20T21:19:21.227 回答
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 + 动态(第一个示例)=> 40 毫秒

通用 + 动态(第二个示例)=> 90 毫秒

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

于 2013-06-04T08:32:39.200 回答
0

您可以执行以下操作:

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

    eventHandler(sender, args);
}

不过,我不确定这是否会比使用 DynamicInvoke 更快。

您必须在某处使用反射。如果可以保证每个委托只有一个订阅者,那么您可以在创建时直接使用Delegate.MethodEventHandler属性,但由于它们是事件,它们可能有多个订阅者......

于 2011-01-20T20:46:03.513 回答