デリゲートよりもイベントを使用することの利点は、構文上の砂糖以外にはありません。誤解しているかもしれませんが、イベントはデリゲートのプレースホルダーにすぎないようです。
違いと、いつ使用するかを説明してください。長所と短所は何ですか?私たちのコードはイベントに根ざしているので、その根底に行きたいと思います。
イベントでデリゲートを使用するのはいつですか?両方の実際の経験を、たとえば量産コードで述べてください。
デリゲートよりもイベントを使用することの利点は、構文上の砂糖以外にはありません。誤解しているかもしれませんが、イベントはデリゲートのプレースホルダーにすぎないようです。
違いと、いつ使用するかを説明してください。長所と短所は何ですか?私たちのコードはイベントに根ざしているので、その根底に行きたいと思います。
イベントでデリゲートを使用するのはいつですか?両方の実際の経験を、たとえば量産コードで述べてください。
回答:
技術的な観点から、他の回答が違いに対処しています。
セマンティクスの観点からは、イベントは特定の条件が満たされたときにオブジェクトによって発生するアクションです。たとえば、私のStockクラスにはLimitというプロパティがあり、株価がLimitに達したときにイベントを発生させます。この通知はイベントを介して行われます。誰かがこのイベントを実際に気にかけてサブスクライブするかどうかは、オーナークラスの懸念を超えています。
デリゲートは、C / C ++用語のポインターに類似した構成を説明するより一般的な用語です。.Netのすべてのデリゲートはマルチキャストデリゲートです。セマンティクスの観点から、これらは一般的に一種の入力として使用されます。特に、これらはStrategy Patternを実装するのに最適な方法です。たとえば、オブジェクトのリストをソートする場合、2つのオブジェクトを比較する方法を実装に伝えるために、メソッドにコンパレータ戦略を提供できます。
私は製品コードで2つの方法を使用しました。特定のプロパティが満たされると、大量のデータオブジェクトが通知します。最も基本的な例では、プロパティが変更されるたびに、PropertyChangedイベントが発生します(INotifyPropertyChangedインターフェイスを参照)。コードでデリゲートを使用して、特定のオブジェクトを文字列に変換するさまざまな戦略を提供しました。この特定の例は、ユーザーに表示する特定のオブジェクト型の実装の栄光のあるToString()リストでした。
キーワードevent
は、マルチキャストデリゲートのスコープ修飾子です。これとマルチキャストデリゲートを宣言するだけの実際的な違いは次のとおりです。
event
インターフェースで使用できます。public event
)によって指定されたとおりです。関心のある問題として、を適用+
し-
てマルチキャストデリゲートに適用できます。これは、デリゲートをイベントに組み合わせて割り当てるための+=
およびの-=
構文の基本です。これらの3つのスニペットは同等です。
B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B + C;
直接割り当てと組み合わせ割り当ての両方を示すサンプル2。
B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B;
A += C;
サンプル3:より身近な構文。すべてのハンドラーを削除するためのnullの割り当てに精通している可能性があります。
B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = null;
A += B;
A += C;
プロパティと同様に、イベントには完全な構文があり、誰も使用しません。この:
class myExample
{
internal EventHandler eh;
public event EventHandler OnSubmit
{
add
{
eh = Delegate.Combine(eh, value) as EventHandler;
}
remove
{
eh = Delegate.Remove(eh, value) as EventHandler;
}
}
...
}
... これとまったく同じです:
class myExample
{
public event EventHandler OnSubmit;
}
addおよびremoveメソッドは、VB.NETが使用する(演算子のオーバーロードなし)どちらかといえば堅固な構文でより目立ちます。
イベントはメタデータでそのようにマークされます。これにより、WindowsフォームやASP.NETデザイナーなどが、デリゲートタイプの単なるプロパティからイベントを区別し、適切なサポートを提供することができます(特に、[プロパティ]ウィンドウの[イベント]タブに表示されます)。
デリゲート型のプロパティとのもう1つの違いは、ユーザーはイベントハンドラーの追加と削除しかできないのに対し、デリゲート型のプロパティでは値を設定できることです。
someObj.SomeCallback = MyCallback; // okay, replaces any existing callback
someObj.SomeEvent = MyHandler; // not okay, must use += instead
これは、イベントサブスクライバーを分離するのに役立ちます。ハンドラーをイベントに追加できます。ハンドラーを同じイベントに追加でき、誤ってハンドラーを上書きすることはありません。
イベントは通常マルチキャストデリゲートで実装されますが、そのような方法で使用する必要はありません。クラスがイベントを公開する場合、それはクラスが2つのメソッドを公開することを意味します。それらの意味は、本質的には:
クラスが公開するイベントを処理する最も一般的な方法は、マルチキャストデリゲートを定義し、上記のメソッドに渡されるデリゲートを追加/削除することですが、そのように動作する必要はありません。残念ながら、イベントアーキテクチャは、代替アプローチをよりクリーンにするいくつかのことを実行できません(たとえば、サブスクリプションメソッドがMethodInvokerを返します。断然最も一般的なアプローチです。
違いを理解するには、この2つの例を見てください。
デリゲートの例(この場合のアクションは、値を返さない一種のデリゲートです)
public class Animal
{
public Action Run {get; set;}
public void RaiseEvent()
{
if (Run != null)
{
Run();
}
}
}
デリゲートを使用するには、このようなことをする必要があります
Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();
このコードはうまく機能しますが、いくつかの弱点がある可能性があります。
例えば私がこれを書いたら
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;
コードの最後の行で、以前の動作を1つ欠けているだけでオーバーライドしました+
(の+
代わりに使用しました+=
)
もう1つの弱点は、クラスを使用するすべてのクラスが、それを呼び出すだけでAnimal
レイズできるRaiseEvent
ことanimal.RaiseEvent()
です。
この弱点を回避するにevents
は、c#で使用できます。
あなたの動物のクラスはこのように変わります
public class ArgsSpecial :EventArgs
{
public ArgsSpecial (string val)
{
Operation=val;
}
public string Operation {get; set;}
}
public class Animal
{
public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it
public void RaiseEvent()
{
Run(this, new ArgsSpecial("Run faster"));
}
}
イベントを呼び出す
Animale animal= new Animal();
animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
違い:
ノート
EventHandlerは、次のデリゲートとして宣言されています。
public delegate void EventHandler (object sender, EventArgs e)
送信者(オブジェクトタイプ)とイベント引数を受け取ります。静的メソッドからのものである場合、送信者はnullです。
EventHAndler
代わりにこの例を使用することもできますEventHandler<ArgsSpecial>
EventHandlerに関するドキュメントについては、こちらを参照してください
Edit#1 イベントとvs.versaではいつデリゲートを使用しますか?両方の実際の経験を、たとえば量産コードで述べてください。
自分のAPIを設計するとき、メソッドまたはクラスのコンストラクターにパラメーターとして渡されるデリゲートを定義します。
Predicate
とAction
代表者がネットジェネリックコレクションクラスに渡されます)これらのデリゲートは、通常、実行時にオプションではありません(つまり、にすることはできませんnull
)。
私はイベントを使用しない傾向があります。私は、使用イベントを行う場所が、私はそれらを使用し、必要に応じへのシグナル伝達事象を、ゼロ1、またはそれ以上のクライアントかもしれません興味がある、すなわち、それは、クラス(例えばという意味行ったときにSystem.Windows.Form
クラス)が存在しなければならないが、任意のクライアントが持っているかどうかを実行しますイベントにイベントハンドラーを追加しました(フォームの「マウスダウン」イベントは存在しますが、外部クライアントがそのイベントにイベントハンドラーをインストールするかどうかはオプションです)。
技術的な理由はありませんが、UIスタイルのコード、つまりより高いレベルのコードでイベントを使用し、コードの奥にあるロジックにはデリゲートを使用します。私はあなたもどちらでも使用できると言いますが、私はこの使用パターンが論理的に健全であると思います。
編集:私は私が持っている使用パターンの違いはそれだと思う、私はイベントを無視することは完全に許容できると思うイベントはそれを無視します。それが私がUI、一種のJavaScript /ブラウザイベントスタイルに使用する理由です。ただし、デリゲートがある場合、誰かがデリゲートのタスクを処理することを本当に期待し、処理されない場合は例外をスローします。
イベントとデリゲートの違いは、私が思っていたよりもはるかに小さいです。件名に非常に短いYouTube動画を投稿しました:https : //www.youtube.com/watch?v=el-kKK-7SBU
お役に立てれば!
イベントの代わりにデリゲートのみを使用する場合、サブスクライバーは、以下の画像に示すように、デリゲート自体をclone()、invoke()する機会があります。それは正しくありません。
これが、b / wイベントとデリゲートの主な違いです。加入者には1つの権限しかありません。つまり、イベントを聞く
ConsoleLogクラスは、EventLogHandlerを介してログイベントをサブスクライブしています
public class ConsoleLog
{
public ConsoleLog(Operation operation)
{
operation.EventLogHandler += print;
}
public void print(string str)
{
Console.WriteLine("write on console : " + str);
}
}
FileLogクラスは、EventLogHandlerを介してログイベントをサブスクライブしています
public class FileLog
{
public FileLog(Operation operation)
{
operation.EventLogHandler += print;
}
public void print(string str)
{
Console.WriteLine("write in File : " + str);
}
}
操作クラスはログイベントを公開しています
public delegate void logDelegate(string str);
public class Operation
{
public event logDelegate EventLogHandler;
public Operation()
{
new FileLog(this);
new ConsoleLog(this);
}
public void DoWork()
{
EventLogHandler.Invoke("somthing is working");
}
}