【问题标题】:Using MulticastDelegate as parameter while avoiding DynamicInvoke使用 MulticastDelegate 作为参数,同时避免 DynamicInvoke
【发布时间】:2011-06-12 17:09:43
【问题描述】:

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

【问题讨论】:

  • 该旧代码升级到 EventHandler 的时间。在那之前,没有。
  • 真正的代码不是直接使用EventArgs,而是使用自定义子类。但是,我看不出有任何理由不应该为每个分派的事件使用相同的委托——然后我可以从 MulticastDelegate 更改为有问题的委托类型。

标签: c# events delegates multicastdelegate


【解决方案1】:

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

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 表示那里的一些创新,但这是否有助于调度单个事件?我想可以打电话给DispatchEvent(ObjectWasCreated.Invoke)..
【解决方案2】:

一种简单的替代方法是使用 Action&lt;,&gt;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 毫秒

【讨论】:

  • 感谢您的想法和性能指标。我没想到它会表现得这么好。
【解决方案3】:

你可以这样做:

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

【讨论】:

  • -1。这对 OP 有何帮助?他没有EventHandler 类型,而是自定义委托。
猜你喜欢
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-23
  • 1970-01-01
相关资源
最近更新 更多