74

ハンドラーがアタッチされていない C# でイベントを発生させることはできません。そのため、各呼び出しの前に、イベントが null かどうかを確認する必要があります。

if ( MyEvent != null ) {
  MyEvent( param1, param2 );
}

コードをできるだけクリーンに保ち、これらの null チェックを取り除きたいと考えています。少なくとも私の場合は、パフォーマンスに大きな影響を与えるとは思いません。

MyEvent( param1, param2 );

現在、空のインラインハンドラーを各イベントに手動で追加することでこれを解決しています。私はそれを行うことを覚えておく必要があるため、これはエラーが発生しやすいです。

void Initialize() {
  MyEvent += new MyEvent( (p1,p2) => { } );
}

リフレクションといくつかの CLR マジックを使用して、特定のクラスのすべてのイベントに対して空のハンドラーを自動的に生成する方法はありますか?

4

8 に答える 8

160

私は別の投稿でこれを見て、恥知らずにそれを盗み、それ以来私のコードの多くでそれを使用しました:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

//Let you do this:
public void DoSomething() {
    Click(this, "foo");
}

//Instead of this:
public void DoSomething() {
    if (Click != null) // Unnecessary!
        Click(this, "foo");
}

*このテクニックの起源を知っている人がいたら、コメントに投稿してください。私は、情報源が正当な信用を得ていると本当に信じています。

編集:この投稿から取得しましたC#の隠し機能?

于 2008-12-04T13:44:15.223 に答える
61

表記:

if ( MyEvent != null ) {
  MyEvent( param1, param2 );
}

スレッドセーフではありません。あなたはこのようにそれをするべきです:

EventHandler handler = this.MyEvent;
if ( null != handler ) { handler( param1, param2 ); }

これは面倒なので、ヘルパーメソッドを実行できることを理解しています。

static void RaiseEvent( EventHandler handler, object sender, EventArgs e ) {
    if ( null != handler ) { handler( sender, e ); }
}

次に、次のように呼び出します。

RaiseEvent( MyEvent, param1, param2 );

C#3.0を使用している場合は、ヘルパーメソッドを拡張メソッドとして宣言できます。

static void Raise( this EventHandler handler, object sender, EventArgs e ) {
    if ( null != handler ) { handler( sender, e ); }
}

次に、次のように呼び出します。

MyEvent.Raise( param1, param2 );

また、他のイベントハンドラーの次の拡張/ヘルパーメソッドを作成することもできます。例えば:

static void Raise<TEventArgs>( this EventHandler<TEventArgs> handler,
    object sender, TEventArgs e ) where TEventArgs : EventArgs
{
    if ( null != handler ) { handler( sender, e ); }
}
于 2008-12-04T13:53:10.557 に答える
6

さまざまなイベントハンドラーに複数の拡張メソッドは必要ありません。必要なのは次の1つだけです。

public static class EventHandlerExtensions {
  public static void Raise<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs {
    if (handler != null) handler(sender, args);
  }
}
于 2009-03-31T15:11:25.390 に答える
6

あなたは次のように書くことができます:

MyEvent += delegate { };

あなたがやりたいことが正しいかわかりません。

于 2008-12-04T13:44:39.920 に答える
2

これは、イベントを消費しているコードが、イベントを含むオブジェクトがデフォルトでアクションを使用してコーディングされていることを期待しているという点で、悪い考えです。あなたのコードが他の誰かによって他のどこかで使われることは決してないのなら、私はあなたがそれで逃げることができると思います。

于 2008-12-04T13:53:46.170 に答える
1

残念ながら、C#イベント宣言には、多くのよく知られた安全上の問題と非効率性が含まれています。デリゲートを安全に呼び出し、スレッドセーフな方法でデリゲートを登録/登録解除するために、デリゲートにいくつかの拡張メソッドを設計しました

古いイベント発生コード:

if (someDelegate != null) someDelegate(x, y, z);

新しいコード:

someDelegate.Raise(x, y, z);

古いイベント登録コード:

event Action fooEvent;
...
lock (someDummyObject) fooEvent += newHandler;

新しいコード:

Action fooEvent;
...
Events.Add(ref fooEvent, newHandler);

ロックは必要ありません。イベントをロックするためにコンパイラが挿入したダミーオブジェクトは使用されません。

于 2011-01-28T02:00:11.863 に答える
-1

PostSharpを使用して、ビルド時にこの魔法を追加できます。それが最善の方法です。

于 2010-07-23T20:44:59.900 に答える