web-dev-qa-db-ja.com

Action <T> vsデリゲートイベント

開発者が以下のコードをかなり代わりに使用しているのを見てきました。これらの正確な違いは何ですか?また、どれが標準を満たしますか? ActionFunc<T>もデリゲートであるため、同じです:

public event Action<EmployeeEventAgs> OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}

VS

public delegate void GoOnLeave(EmployeeEventAgs e);
public event GoOnLeave OnLeave;
public void Leave()
{
    OnLeave(new EmployeeEventAgs(this.ID));
}
58
Bhaskar

Fwiw、どちらの例も標準の.NET規則を使用していません。 EventHandler<T>ジェネリックはイベントを宣言する必要があります。

public event EventHandler<EmployeeEventArgs> Leave;

「On」プレフィックスは、イベントを発生させるプロテクトメソッド用に予約する必要があります。

protected virtual void OnLeave(EmployeeEventArgs e) {
    var handler = Leave;
    if (handler != null) handler(this, e);
}

この方法でhaveを実行することはありませんが、誰でもすぐにパターンを認識し、コードを理解し、その使用方法とカスタマイズ方法を知ることができます。

また、カスタムデリゲート宣言とAction<>の選択を強制されないという大きな利点があり、EventHandler<>が最適な方法です。あなたの質問に答えます。

51
Hans Passant

次の2行のコードはほぼ同等です。

public event Action<EmployeeEventAgs> Leave;

に比べ:

public event EventHandler<EmployeeEventAgs> Leave;

違いは、イベントハンドラーメソッドのシグネチャです。アクションで最初のアプローチを使用する場合、次のことができます。

public void LeaveHandler(EmployeeEventAgs e) { ... }

そして、これ:

obj.Leave += LeaveHandler;

2番目のアプローチでは、LeaveHandlerの署名が異なる必要があります。

public void LeaveHandler(object sender, EmployeeEventAgs e) { ... }

非常に重要どちらの場合も、eventキーワードがイベントメンバーの宣言に使用されることに注意してください。このように宣言されたイベントメンバは、クラスのフィールドではありませんが、クラスのフィールドではありません。代わりに、コンパイラはevent propertyとして作成します1。イベントプロパティは通常のプロパティに似ていますが、getまたはsetアクセサーがない点が異なります。コンパイラーは、+=および-=割り当て(イベントハンドラーの追加または削除)の左側でのみ使用できるようにします。 既に割り当てられているイベントハンドラを上書きする、または宣言するクラスの外部でイベントを呼び出す itにする方法はありません。

両方の例でイベントキーワードが欠落している場合、エラーまたは警告なしで次の操作を実行できます。

obj.Leave = LeaveHandler;

登録済みのハンドラーを消去し、LeaveHandlerに置き換えます。

さらに、次の呼び出しも実行できます。

obj.Leave(new EmployeeEventAgs());

イベントを作成する場合、上記の2つの状況はanti-patternと見なされます。イベントは所有者オブジェクトのみで呼び出す必要があり、サブスクライバのntraceableの削除を許可しないでください。 eventキーワードは、イベントの正しい使用に固執するのに役立つ.NETのプログラム構造です。

上記を念頭に置いて、EventHandlerキーワードなしでEventHandlerを使用する可能性は低いため、多くの人がeventアプローチに固執すると信じています。アクションの使用範囲は広く、イベントとして使用する場合は自然に見えません。もちろん、後者は個人的な意見です。イベントハンドラーのアプローチは、おそらく私自身のコーディングプラクティスではあまりにもハードワイヤードになってしまったからです。それでも、アクションが適切に使用されている場合、イベントに使用することは犯罪ではありません。


1 イベントプロパティは、次のようなコードを見たときにコンパイラが自動的に生成するものです。

event EventHandler SomeEvent 

以下とほぼ同じコードになります。

private EventHandler _someEvent; // notice the lack of the event keyword!
public event EventHandler SomeEvent
{
    add { _someEvent += value; }
    remove { _someEvent -= value; }
}

次のように記述するイベント呼び出し:

this.SomeEvent(sender, args);

これに変換されます:

this._someEvent(sender, args);
28
Ivaylo Slavov

_Action<T>_はdelegate void ... (T t)とまったく同じです

_Func<T>_はdelegate T ... ()とまったく同じです

22
pdr

アクションは、完全なデリゲート宣言の単なるショートカットです。

public delegate void Action<T>(T obj)

http://msdn.Microsoft.com/en-us/library/018hxwa8.aspx

どちらを使用するかは、組織のコーディング標準/スタイルによって異なります。

6
Darryl Braaten

はい、ActionとFuncは、3.5 clrで定義された単なる便利なデリゲートです。

Action、Func、およびlambdaは、すべて構文上の砂糖であり、デリゲートを使用するのに便利です。

それらについて魔法はありません。この機能を2.0コードに追加するために、単純な2.0アドオンライブラリを作成した人もいます。

4
Sky Sanders

こちらをご覧になることをお勧めします、コンパイラが実際にAction用に生成するものを見るのが最良の説明です。書いたものに機能的な違いはなく、より短く、より便利な構文です。

4
Nick Craver

一般に、それらは同等です。ただし、イベントのタイプにデリゲートを使用するコンテキストでは、規則はEventHandlerを使用することです(TはEventArgsを継承します)。

public event EventHandler<EmployeeEventArgs> Left;

public void Leave()
{
    OnLeft(this.ID);
}

protected virtual void OnLeft(int id)
{
    if (Left != null) {
        Left(new EmployeeEventArgs(id));
    }
}
3
Rafa Castaneda

これらのActionデリゲートとFuncジェネリックデリゲートを自分で作成することもできますが、これらは一般的に有用であるため、それらを作成して.Netライブラリに貼り付けました。

0
Jason Kleban