1

現在、次のコードを使用して、クラスにイベントを実装します。このイベントには、最大 1 つのイベント ハンドラーを登録できます。

private event EventHandler<EventArgs> e_Foo;

public event EventHandler<EventArgs> Foo {
    add {
        if (e_Foo != null && e_Foo.GetInvocationList().Any())
            throw new InvalidOperationException("Only one event handler may be registered at a time.");
        e_Foo += value;
    }
    remove {
        e_Foo -= value;
    }
}

private void OnFoo() {
    if (e_Foo != null)
        e_Foo(this, EventArgs.Empty);
}
  • より良い方法はありますか?
  • これをクラスにまとめて、多くのコードをコピーして貼り付ける必要がないようにする方法はありますか?
4

4 に答える 4

2

イベントは、特別なセマンティクスを持つデリゲート プロパティを公開するための特別な方法にすぎません。値を設定する代わりに、ハンドラーを追加および削除します。この動作がうまくいかない場合、それをイベントから削除しようとすると、不要な複雑さが生じるだけです。代わりに、コールバックをデリゲート プロパティとして直接公開することで、最初から不要な動作を追加することを単純に避けてみませんか?

public Action<T1, T2> Foo {get; set;}

private void OnFoo(T1, T2) 
{
    var handler = Foo;
    if(handler != null) handler(T1, T2);
}

このように、誰かが設定OnFooすると、通常のプロパティ セマンティクスが使用され、デリゲート インスタンスがパイルにスローされるのではなく置き換えられます。マルチキャストを取り除くわけではありませんが、とにかくそれが本当にあなたの問題であるようには思えません。

于 2012-12-22T13:58:37.040 に答える
2

これは実際にはコメントである必要がありますが、コードを記述する必要があります。

private void OnFoo() {
    if (e_Foo != null)
        e_Foo(this, EventArgs.Empty);
}

チェックと実際の呼び出しの間で呼び出しリストが変更される可能性があるため、競合状態が発生する可能性があります。null を呼び出してしまう可能性があります。そのはず:

private void OnFoo() {
    var fuFoo = e_Foo;
    if (fuFoo != null)
        fuFoo(this, EventArgs.Empty);
}

注: 2020 年です。C# 6 以降、null 条件演算子が使用されています。

これを使用して、以前のコードをより簡単な方法で表現できます。

private void OnFoo() {
    e_Foo?.Invoke(this, EventArgs.Empty);
}

エラーが発生しにくい方法がより良い方法だと思います。私の勝ち!

于 2012-09-19T00:27:47.933 に答える
1

コードを大幅に削減することはできないと思いますが、次のように、作業を行うか、ハンドラーを返すメソッドにチェックを入れることができます。

public EventHandler<T> HookUp<T>(EventHandler<T> myEvent, EventHandler<T> myMethod)
    where T : EventArgs
{
    if (myEvent != null && myEvent.GetInvocationList().Any())
        throw new InvalidOperationException("Only one event handler may be registered at a time.");
    return myMethod;
}

private event EventHandler<EventArgs> e_Foo;

public event EventHandler<EventArgs> Foo
{
    add { e_Foo += HookUp(e_Foo, value); }
    remove { e_Foo -= value; }
}

いくつかの拡張メソッドでそのすべてのロジックを持つインターフェイスを実装するか、抽象クラスを継承することができます。ただし、必要なイベント数 ( ISingleSubscriberOneISingleSubscriberTwoISingleSubscriberThreeなど) ごとに複数のインターフェイスが必要になります。

于 2012-12-22T13:42:01.693 に答える
0

あなたのシナリオでそれが可能かどうかはわかりませんが、イベントコードをアクション変数に割り当て、イベントをそのアクションにリンクすることをお勧めします。その場合、ユーザーはアクションを変更することしかできず、私のイベントに登録されているイベントを実際に変更することはできません。イベントはアクションにリンクするだけなので、アクションを変更できますが、同時に2つを持つことはできません。

ちょっとした考え。まだコーヒーを飲んでいないので、これはまったく適切ではないかもしれません...

于 2012-12-22T14:17:54.633 に答える