8

たとえば、ベース イベント公開メソッドがあります。

    protected virtual OnSomeEvent(EventArgs e)
    {
        var handler = SomeEvent;
        if (handler != null)
        {
            handler(this, e);
            // handler(this, new EventArgs());// EDIT: Yes it should be
                                           // handler(this, e),
                                           // ignore this one :D
        }
    }

OnSomeEvent発生時に追加のイベントをオーバーライドして発生させる派生クラスの場合:

    protected override OnSomeEvent(EventArgs e)
    {
        base.OnSomeEvent(e);

        if (ExtendedEvent != null)
        {
            OnExtendedEvent(e);
        }
    }

    protected void OnExtendedEvent(EventArgs e)
    {
       // some stuff done
       // new information the ExtendedEventArgs object needs 
       //  is not available until this point

       ExtendedEvent(this, new ExtendedEventArgs(someStuff, someOtherStuff));
    }

そして、派生がこのように進むと、それを必要とする派生クラスの世代ごとに新しい派生 EventArgs が作成されます。ただしEventArgs、.NET フレームワークのさまざまな派生物は変更可能 (セッターなし) に設計されていないようです。これにより、オブジェクトが EventArgs の単一のインスタンスを保持し、それを変更することが妨げられます。

したがって、このようなイベントが発生するたびに、関連するすべてのEventArgsオブジェクトにメモリが再割り当てされます。イベントが 1 秒間に何十回もトリガーされる可能性がある (OnPaintコントロールのイベントなど) グラフィックが集中するアプリケーションでは、これは本当に良い方法でしょうか?

次のことが可能になるように、いくつかの変更を加えて変更可能にする必要OnExtendedEvent()ExtendedEventArgsありますか?

    protected ExtendedEventArgs extendedArgs = ExtendedEventArgs.Empty;
    protected void OnExtendedEvent(EventArgs e)
    {
       // some stuff done
       // new information the ExtendedEventArgs object needs 
       //  is not available until this point

       extendedArgs.someProperty1 = someStuff;
       extendedArgs.someProperty2 = someOtherStuff;

       ExtendedEvent(this, extendedArgs);
    }

編集: サンプルコードを修正しました。より明確になるはずです。

4

3 に答える 3

5

まず、とにかく無視するだけなのに、なぜ EventArgs 引数を発火メソッドに使用するのでしょうか? これは本当の無駄ですが、リソースの消費は、メソッドが呼び出し元に嘘をつくことよりも問題は少なくなります。引数を渡すだけで、起動メソッドには EventArgs オブジェクトを作成するための関連情報がアクセスできない可能性があります。

protected virtual OnSomeEvent(EventArgs e)
{
    var handler = SomeEvent;
    if (handler != null)
    {
        handler(this, e);
    }
}

EventArgs オブジェクトにサブスクライバーに伝える意味のある情報がない場合は、EventArgs.Empty を使用してください。それが目的です。カスタム EventArgs クラスについても同じパターンに従うことができますが、正直なところ、何も心配する必要はありません。EventArgs オブジェクトの作成がアプリケーションのボトルネックになることは決してありません。ボトルネックである場合は、設計上の問題があります。

于 2010-01-29T00:31:06.320 に答える
3

イベント引数に値があるため、起動するたびに新しい不変オブジェクトを作成します。

主な理由は、既存のイベントの処理中に新しいイベントが再度発生した場合にどうなるかということです。

これは、マルチスレッドアプリケーションで発生する可能性がありますが、次の例に示すように、シングルスレッドでも発生する可能性があります。

最初のイベントは、次の値で発生します。

extendedArgs.someProperty1 = "Fire 1";
extendedArgs.someProperty2 = "Fire 1 Other Stuff";

次に、どういうわけか、最初のイベントハンドラーが何かを実行すると、次の引数を使用してイベントが再度発生します。

extendedArgs.someProperty1 = "Fire 2";
extendedArgs.someProperty2 = "Fire 2 Other Stuff";

すべてのイベントハンドラーは2番目のイベント用であり、処理されます。これで、最初のイベントの残りのイベントハンドラーの処理に戻ります。

これで、同じオブジェクトが使用されるため、最初のイベントのすべてのイベントハンドラーは、2番目のイベントが値を上書きしたため、someProperty1として「Fire2」を持ちます。

@nobugzが述べたように、短命のゴミを作成することを恐れないでください。

于 2010-01-29T03:10:31.717 に答える
1

私はあなたのOnExtendedEventコードに少し混乱しています - イベントを として再ディスパッチするつもりSomeEventですか?

クライアントがイベント ハンドラーを追加すると、次のように、イベントの処理中にイベント ハンドラーを削除できることが期待されます。

someObject.SomeEvent += OnSomeEvent;
// ...
private void OnSomeEvent(object sender, EventArgs e)
{
    someObject.SomeEvent -= OnSomeEvent;
}

標準のディスパッチ方法に従わない場合、このコードは例外をスローし、コードを使用している人を非常に驚かせます。

于 2010-01-29T00:21:26.630 に答える