メソッドへのポインターとしてのC#のデリゲートの概念を理解していると思いますが、それらを使用することをお勧めする良い例を見つけることができません。デリゲートを使用した方がはるかにエレガント/優れている、または他の方法を使用して解決できない例は何ですか?
12 に答える
.NET 1.0 の委任:
this.myButton.Click += new EventHandler(this.MyMethod);
.NET 2.0 の委任:
this.myOtherButton.Click += delegate {
var res = PerformSomeAction();
if(res > 5)
PerformSomeOtherAction();
};
それらはかなり便利なようです。どうですか:
new Thread(new ThreadStart(delegate {
// do some worker-thread processing
})).Start();
私は主に、簡単な非同期プログラミングのために を使用しています。デリゲートの Begin... メソッドを使用してメソッドを開始するのは、起動して忘れたい場合に非常に簡単です。
インターフェイスが使用できない場合、デリゲートをインターフェイスのように使用することもできます。たとえば、COM クラス、外部 .Net クラスなどからメソッドを呼び出します。
代表とは具体的に何を指しますか?以下に、それらを使用できる 2 つの方法を示します。
void Foo(Func<int, string> f) {
//do stuff
string s = f(42);
// do more stuff
}
と
void Bar() {
Func<int, string> f = delegate(i) { return i.ToString(); }
//do stuff
string s = f(42);
// do more stuff
}
2 番目のポイントは、新しい関数をその場でデリゲートとして宣言できることです。これは主にラムダ式に置き換えることができ、1) 別の関数に渡したい、または 2) 繰り返し実行したい小さなロジックがある場合に便利です。LINQ が良い例です。すべての LINQ 関数は、ラムダ式を引数として取り、動作を指定します。たとえば、リスト内のすべての要素に対して ToString() を呼び出しますList<int> l
。l.Select(x=>(x.ToString())
そして、私が書いたラムダ式はデリゲートとして実装されています。
最初のケースは、Select の実装方法を示しています。デリゲートを引数として取り、必要に応じて呼び出します。これにより、呼び出し元は関数の動作をカスタマイズできます。再び Select() を例にとると、関数自体は、渡されたデリゲートがリスト内のすべての要素で呼び出され、それぞれの出力が返されることを保証します。そのデリゲートが実際に何をするかは、あなた次第です。これにより、驚くほど柔軟で一般的な機能になります。
もちろん、イベントのサブスクライブにも使用されます。簡単に言えば、デリゲートを使用すると、関数を参照して、関数呼び出しで引数として使用したり、変数に割り当てたり、その他の好きなことを行うことができます。
イベントは最も明白な例です。オブザーバー パターンが Java (インターフェイス) と C# (デリゲート) でどのように実装されているかを比較します。
また、新しい C# 3 機能 (ラムダ式など) の多くはデリゲートに基づいており、その使用法をさらに簡素化します。
たとえば、マルチスレッド アプリで。複数のスレッドで何らかのコントロールを使用する場合は、デリゲートを使用する必要があります。申し訳ありませんが、コードは VisualBasic です。
最初にデリゲートを宣言します
Private Delegate Sub ButtonInvoke(ByVal enabled As Boolean)
複数のスレッドからボタンを有効/無効にする関数を書く
Private Sub enable_button(ByVal enabled As Boolean)
If Me.ButtonConnect.InvokeRequired Then
Dim del As New ButtonInvoke(AddressOf enable_button)
Me.ButtonConnect.Invoke(del, New Object() {enabled})
Else
ButtonConnect.Enabled = enabled
End If
End Sub
条件を評価したり、選択を返したりする関数を提供するために、LINQ、特にラムダ式で常に使用しています。また、それらを使用して、2 つのアイテムを比較して並べ替える機能を提供します。この後者は、デフォルトの並べ替えが適切である場合とそうでない場合がある一般的なコレクションにとって重要です。
var query = collection.Where( c => c.Kind == ChosenKind )
.Select( c => new { Name = c.Name, Value = c.Value } )
.OrderBy( (a,b) => a.Name.CompareTo( b.Name ) );
デリゲートの利点の 1 つは、非同期実行にあります。
メソッドを非同期的に呼び出すと、いつ実行が終了するかわからないため、最初のメソッドの実行が完了したときに呼び出される別のメソッドを指すデリゲートをそのメソッドに渡す必要があります。2 番目の方法では、実行が完了したことを通知するコードを記述できます。
技術的にデリゲートは、特定の署名と戻り値の型を持つメソッドをカプセル化するために使用される参照型です
他のいくつかのコメントは非同期の世界に触れました...しかし、そのようなことの私のお気に入りの「フレーバー」が言及されているので、とにかくコメントします:
ThreadPool.QueueUserWorkItem(delegate
{
// This code will run on it's own thread!
});
また、デリゲートの大きな理由は「コールバック」です。私が少しの機能を(非同期的に)作成し、何らかのメソッドを呼び出してほしいとしましょう(「AlertWhenDone」としましょう)...次のように「デリゲート」をメソッドに渡すことができます:
TimmysSpecialClass.DoSomethingCool(this.AlertWhenDone);
winforms や asp.net を使用したことがある場合はおなじみのイベントでの役割以外に、デリゲートはクラスをより柔軟にするのに役立ちます (LINQ での使用方法など)。
物事を「見つける」ための柔軟性はかなり一般的です。物のコレクションがあり、物を見つける方法を提供したいと考えています。誰かが物事を見つけたいと思うかもしれない方法をそれぞれ推測するのではなく、呼び出し元がアルゴリズムを提供できるようにして、コレクションを検索できるようにすることができます。
簡単なコード サンプルを次に示します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Delegates
{
class Program
{
static void Main(string[] args)
{
Collection coll = new Collection(5);
coll[0] = "This";
coll[1] = "is";
coll[2] = "a";
coll[3] = "test";
var result = coll.Find(x => x == "is");
Console.WriteLine(result);
result = coll.Find(x => x.StartsWith("te"));
Console.WriteLine(result);
}
}
public class Collection
{
string[] _Items;
public delegate bool FindDelegate(string FindParam);
public Collection(int Size)
{
_Items = new string[Size];
}
public string this[int i]
{
get { return _Items[i]; }
set { _Items[i] = value; }
}
public string Find(FindDelegate findDelegate)
{
foreach (string s in _Items)
{
if (findDelegate(s))
return s;
}
return null;
}
}
}
出力
は
テスト
データベースへの外部呼び出しを処理するときにデリゲートを使用する利点はありますか?
たとえば、 A をコーディングできます。
static void Main(string[] args) {
DatabaseCode("test");
}
public void DatabaseCode(string arg) {
.... code here ...
}
コード B で改善される:
static void Main(string[] args) {
DatabaseCodeDelegate slave = DatabaseCode;
slave ("test");
}
public void DatabaseCode(string arg) {
.... code here ...
}
public delegate void DatabaseCodeDelegate(string arg);
主観のようですが、意見の対立が激しいところ?
デリゲートで解決できるもので、他の方法では解決できないものは実際にはありませんが、デリゲートはより洗練されたソリューションを提供します。
デリゲートを使用すると、必要なパラメーターがある限り、任意の関数を使用できます。
別の方法として、プログラム内で一種のカスタム ビルド イベント システムを使用することがよくあります。これにより、余分な作業が発生し、バグが忍び寄る領域が増えます。