1

私はこれを少し考えすぎているかもしれませんが、次のことを行う方法/最良の方法を特定するのにいくらかの助けを借りることができます.

別のクラスのプロパティであるオブジェクトにアタッチされたイベント ハンドラーがあります。私のイベント ハンドラーでは、イベントを引き起こしたオブジェクトに関する追加のメタデータ (つまり、イベントが含まれているオブジェクトの ID) が必要です。送信者とイベント情報から、必要な情報を取得する方法がありません。私の傾向は、これがキャプチャされた変数を使用するのに適した場所になるということでしたが、実装のアイデアがわかりません。

コードで説明するために、イベント ハンドラーがあります。

void MyEventHandler(object sender, EventArgs e){
    //Do Stuff here
}

(注記として、ここではベース EventArgs を使用していますが、実際の実装では特殊なサブクラスであり、イベントはジェネリック EventHandler を使用して宣言されています)

私は現在、このようにそれを添付しています:

topObject.SubObject.EventToHandle += MyEventHandler;

後で次のように切り離します。

topObject.SubObject.EventToHandle -= MyEventHandler;

イベントを処理するときに topObject の ID が必要なので、MyEventHandler を次の署名を持つように変更します。

void MyEventHandler(int id, object sender, EventArgs e)

次のようにイベント ハンドラーをアタッチします。

topObject.SubObject.EventToHandle += (s,e) => MyEventHandler(topObject.ID, s,e);

それに関する私の懸念は2つあります。

  1. これがアタッチされている関数の外に出ると、ハンドラーが削除されずに実際に消えるスコープに問題がありますか。過去に、ラムダ式を使用したときにイベント ハンドラーが消えてしまう奇妙なエラーを見たことがあります。常にではなく、場合によってはそうです。それらのケースが何であるかについて誰かが私に教えてくれるので、私が持っていた構文をいつ安全に使用できるかがわかります。
  2. 正確には思い出せませんが、作成される暗黙的なオブジェクトが同じではないため、この構文を使用した場合、イベント ハンドラーを削除することはできないと思います。

これら 2 つの懸念事項があるため、アクションを作成してアクションを保存し、イベント ハンドラーを削除する必要があるまでそれを使用することを考えました。私は次のことをしました:

Action<object, EventArgs> handler = (s,e) => MyEventHandler(topObject.ID, s,e);
topObject.SubObject.EventToHandle += handler;

アクションをイベント ハンドラーにキャストできないことがわかりました。イベント ハンドラーをデタッチできることを保証するこの変換を行う簡単な方法はありますか? 私はこれを考えすぎているだけですか/これを行うために今見ていない方法はありますか?

4

4 に答える 4

1

既存のイベントハンドラーをラップしてオブジェクトIDを提供するすべての優れたラッパー関数を作成できますが、イベントのサブスクライブを解除するには、結果のデリゲートを明示的に格納する必要があります。

醜いラッパーなしでそれを行うために私が見る唯一の良い方法は、リアクティブエクステンションを使用することです。これにより、基本的にイベントをIObservableに変換でき、結果のIObservableに任意の演算子を適用できます(たとえば、Selectがこの場合にジョブを実行します)。しかし、それでもそれほどエレガントではありません。

于 2010-12-08T23:26:17.237 に答える
0

イベントハンドラーが最上位のオブジェクトのIDを必要とする場合、それらを相互に認識させるために、デザインの抽象化レイヤーを壊すことはないと思います。

つまり、イベントハンドラーは次のようになります。

void Handler(object sender, EventArgs e)
{
     var s = (SubObject) sender;
     int id = s.TopObject.ID;

     // do something with id...
}

送信者と引数の規則に従って、イベントの署名を保持します。

于 2010-12-08T23:37:29.450 に答える
0

イベントの署名は変更しないでください。CLRでは、技術的にはイベントの任意の署名が許可されていますが、フレームワーク全体が署名を持つイベントで設計されているのには理由があります(object sender, EventArgs args)。実際、このシグニチャに違反するイベントにはFxCopルールがあります。CA1009:イベントハンドラを正しく宣言します

イベントハンドラーメソッドは2つのパラメーターを取ります。1つ目はSystem.Object型で、「sender」という名前です。これは、イベントを発生させたオブジェクトです。2番目のパラメーターのタイプはSystem.EventArgsで、名前は「e」です。

いくつかの解決策(代替案)があります:

  • topObject.IDをカスタムEventArgsのメンバーとして渡します。
  • topObject.IDをカプセル化するラッパーオブジェクトを作成し、イベントハンドラーをこのオブジェクトのメソッドにフックします。
  • topObject.IDへの参照をスコープ内に保持できるクロージャスコープを使用します(これは上記の方法と同じですが、重労働はコンパイラーによって行われます)
于 2010-12-08T23:39:01.307 に答える
0

イベントを発生させるクラスのイベント ハンドラー シグネチャは、次のようにする必要があります。

protected void OnMyEvent(object sender, EventArgs  e)
{
    ....
}

また

protected void OnMyEvent(object sender, MyEventArgs  e)
{
    ....
}

この場合、呼び出し元は次のようなコードを実行します。

topObject.SubObject.MyEvent -= OnSubObjectMyEvent;

次のように OnSubObjectMyEvent を実装します (例):

private void OnSubObjectMyEvent(object sender, MyEventArgs e)
{
   int topObjectId = ((SubObjectType)sender).TopObject.Id;
   ...
}

ここで、SubObject には、トップ オブジェクトの ID を取得できる TopObject プロパティがあるとします。

これは、ほとんどの .NET Framework クラスが機能する方法です。このアプローチに問題はありますか?

于 2010-12-08T23:34:59.040 に答える