3

MulticastDelegate同じ署名を持つ多数の(レガシー)デリゲートの1つを参照できるがあります。例えば:

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

簡単な代替方法の 1 つは、カスタム デリゲートの代わりにAction<,>orのような組み込み型を使用して、強力な型を取得することです。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がわかりました:

100万回の試行

MulticastDelegate + 動的 (最初の例) => 40 ミリ秒

汎用 + 動的 (2 番目の例) => 90 ミリ秒

MulticastDelegate + DynamicInvoke (最初に問題で指定) => 940 ミリ秒

于 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 を使用するよりも高速になるかどうかはわかりません。

どこかでリフレクションを使用する必要があります。各デリゲートがサブスクライバーを 1 つだけ持つことが保証されている場合は、を作成するときにDelegate.Methodプロパティを直接使用できますEventHandlerが、それらはイベントであるため、複数のサブスクライバーを持つ可能性があります...

于 2011-01-20T20:46:03.513 に答える