3

クラス内の次の基本的なイベント関連のコードを検討します。

public event EventHandler Updated;

public void OnUpdated() {
    if (Updated != null) Updated(sender: this, e: null)
}

誰もUpdatedイベントをサブスクライブしていない場合、4行目でパフォーマンスが大幅に低下することは望ましくありません(サブスクライバーがサブスクライブする最もきめ細かいイベントを選択して、発生するイベントの数を最小限に抑え、防止することを目的としています)メッセージキューの過負荷)。

サブスクライバーの存在を気にかけ、追跡する必要があります(たとえばif (Updated != null && OnUpdateSubscribed) Updated(sender: this, e: null)、コンパイラー/ランタイムを使用するか、信頼する必要がありますか?

4

1 に答える 1

8

このチェックは、サブスクライブ/アンサブスクライブされるイベントをOnUpdate != null 定義します。実際、ブールチェックとヌルチェックの間に実際の違いはありません。これは、最終的には両方が単なる「ロードフィールド」、「falseの場合は分岐」であるためです。これは、ロジックチェックに関してはnull参照が「false」としてカウントされるためです。心配しています。

私の唯一の提案は次のとおりです。(非常に可能性は低いですが、可能性のある)競合状態を防ぐために、ローカル変数に格納します。

var snapshot = Updated;
if(snapshot != null) snapshot(this, EventArgs.Empty);

だから:いいえ、基本的に:これのオーバーヘッドはありません。

例:

public event EventHandler SomeEvent;
protected virtual void OnSomeEvent()
{
    var snapshot = SomeEvent;
    if (snapshot != null) snapshot(this, EventArgs.Empty);
}

コンパイル先(コメントは私のものです):

.method family hidebysig newslot virtual instance void OnSomeEvent() cil managed
{
    .maxstack 3
    .locals init (
        [0] class [mscorlib]System.EventHandler snapshot)

    // var snapshot = SomeEvent
    L_0000: ldarg.0 
    L_0001: ldfld class [mscorlib]System.EventHandler Foo::SomeEvent
    L_0006: stloc.0

    // if(snapshot == null) goto L_0016;
    L_0007: ldloc.0 
    L_0008: brfalse.s L_0016

    // snapshot(this, EventArgs.Empty);
    L_000a: ldloc.0 
    L_000b: ldarg.0 
    L_000c: ldsfld class [mscorlib]System.EventArgs [mscorlib]System.EventArgs::Empty
    L_0011: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, class [mscorlib]System.EventArgs)

    // L_0016: return;
    L_0016: ret 
}
于 2012-07-18T06:47:01.647 に答える