C#でデリゲートをどのように使用しますか?
C#でデリゲートをどのように使用しますか?
回答:
C#にラムダ式と無名メソッドができたので、デリゲートをさらに使用します。C#1では、ロジックを実装するために常に個別のメソッドが必要でしたが、デリゲートを使用しても意味がありませんでした。最近、私はデリゲートを使用しています:
デリゲートは多くの目的に非常に役立ちます。
そのような目的の1つは、データのシーケンスをフィルタリングするためにそれらを使用することです。このインスタンスでは、1つの引数を受け入れ、デリゲート自体の実装に応じてtrueまたはfalseを返す述語デリゲートを使用します。
これはばかげた例です-あなたはこれからもっと役に立つものを外挿できると確信しています:
using System;
using System.Linq;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<String>
{
"Nicole Hare",
"Michael Hare",
"Joe Hare",
"Sammy Hare",
"George Washington",
};
// Here I am passing "inMyFamily" to the "Where" extension method
// on my List<String>. The C# compiler automatically creates
// a delegate instance for me.
IEnumerable<String> myFamily = names.Where(inMyFamily);
foreach (String name in myFamily)
Console.WriteLine(name);
}
static Boolean inMyFamily(String name)
{
return name.EndsWith("Hare");
}
}
static Boolean inMyFamily(String name)
この方法は、デリゲートです。Whereはデリゲートをパラメーターとして受け取ります。デリゲートに.Where(delegate)
なるメソッドにメソッド名を渡すと、デリゲートは関数ポインタに過ぎないためです。inMyFamilyはブール型を返すため、実際には述語と見なされます。述語はブール値を返す単なるデリゲートです。
別の興味深い答えが見つかりました:
同僚が私にこの質問をしました-.NETのデリゲートのポイントは何ですか?私の答えは非常に短く、彼がオンラインで見つけられなかったものです:メソッドの実行を遅らせるためです。
ソース: LosTechies
LINQが行っているように。
デリゲートを使用して、関数型の変数とパラメーターを宣言できます。
例
「リソース借用」パターンを考えてみましょう。リソースの作成とクリーンアップを制御しながら、クライアントコードがその間にリソースを「借用」できるようにします。
これはデリゲート型を宣言します。
public delegate void DataReaderUser( System.Data.IDataReader dataReader );
このシグネチャに一致する任意のメソッドを使用して、このタイプのデリゲートをインスタンス化できます。C#2.0では、これは暗黙的に、メソッドの名前を使用するだけでなく、匿名メソッドを使用して行うことができます。
このメソッドは、タイプをパラメーターとして使用します。デリゲートの呼び出しに注意してください。
public class DataProvider
{
protected string _connectionString;
public DataProvider( string psConnectionString )
{
_connectionString = psConnectionString;
}
public void UseReader( string psSELECT, DataReaderUser readerUser )
{
using ( SqlConnection connection = new SqlConnection( _connectionString ) )
try
{
SqlCommand command = new SqlCommand( psSELECT, connection );
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while ( reader.Read() )
readerUser( reader ); // the delegate is invoked
}
catch ( System.Exception ex )
{
// handle exception
throw ex;
}
}
}
この関数は、次のように匿名メソッドで呼び出すことができます。無名メソッドは、それ自体の外部で宣言された変数を使用できることに注意してください。これは非常に便利です(例は少し不自然ですが)。
string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";
DataProvider.UseReader( sQuery,
delegate( System.Data.IDataReader reader )
{
Console.WriteLine( sTableName + "." + reader[0] );
} );
多くの場合、デリゲートは1つのメソッドとのインターフェースの代わりに使用できます。これの一般的な例は、オブザーバーパターンです。他の言語では、何かが起こったという通知を受け取りたい場合は、次のように定義します。
class IObserver{ void Notify(...); }
C#では、これはより一般的には、ハンドラーがデリゲートであるイベントを使用して表現されます。次に例を示します。
myObject.SomeEvent += delegate{ Console.WriteLine("..."); };
リストから項目のセットを選択するときなど、述語を関数に渡す必要がある場合にデリゲートを使用するもう1つの優れた場所:
myList.Where(i => i > 10);
上記はラムダ構文の例であり、次のように記述することもできます。
myList.Where(delegate(int i){ return i > 10; });
デリゲートを使用すると便利なもう1つの場所は、ファクトリ関数を登録することです。次に例を示します。
myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);
これが役に立てば幸いです!
私は本当に遅い時期にやって来ますが、今日のデリゲートの目的を理解するのに苦労していて、彼らの目的をうまく説明していると思う同じ出力を与える2つの簡単なプログラムを書きました。
NoDelegates.cs
using System;
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void checkInt(int a) {
Console.Write("checkInt result of {0}: ", a);
if (a < MAX_VALUE && a > MIN_VALUE)
Console.WriteLine("max and min value is valid");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Test.checkInt(1);
Test.checkMax(1);
Test.checkMin(1);
Test.checkInt(10);
Test.checkMax(10);
Test.checkMin(10);
Test.checkInt(20);
Test.checkMax(20);
Test.checkMin(20);
Test.checkInt(30);
Test.checkMax(30);
Test.checkMin(30);
Test.checkInt(254);
Test.checkMax(254);
Test.checkMin(254);
Test.checkInt(255);
Test.checkMax(255);
Test.checkMin(255);
Test.checkInt(256);
Test.checkMax(256);
Test.checkMin(256);
}
}
Delegates.cs
using System;
public delegate void Valid(int a);
public class Test {
public const int MAX_VALUE = 255;
public const int MIN_VALUE = 10;
public static void checkInt(int a) {
Console.Write("checkInt result of {0}: ", a);
if (a < MAX_VALUE && a > MIN_VALUE)
Console.WriteLine("max and min value is valid");
else
Console.WriteLine("max and min value is not valid");
}
public static void checkMax(int a) {
Console.Write("checkMax result of {0}: ", a);
if (a < MAX_VALUE)
Console.WriteLine("max value is valid");
else
Console.WriteLine("max value is not valid");
}
public static void checkMin(int a) {
Console.Write("checkMin result of {0}: ", a);
if (a > MIN_VALUE)
Console.WriteLine("min value is valid");
else
Console.WriteLine("min value is not valid");
Console.WriteLine("");
}
}
public class Driver {
public static void Main(string [] args) {
Valid v1 = new Valid(Test.checkInt);
v1 += new Valid(Test.checkMax);
v1 += new Valid(Test.checkMin);
v1(1);
v1(10);
v1(20);
v1(30);
v1(254);
v1(255);
v1(256);
}
}
少し異なる使い方は、反射を高速化することです。つまり、毎回リフレクションを使用する代わりに、を使用Delegate.CreateDelegate
してメソッド(a MethodInfo
)への(型付き)デリゲートを作成し、代わりにそのデリゲートを呼び出すことができます。これは、ある多くのチェックはすでに行われているので、呼び出しごとに速くなります。
を使用Expression
すると、同じようにその場でコードを作成することもできます。たとえば、Expression
実行時に選択された型の+演算子を表すを簡単に作成できます(言語が提供しないジェネリックの演算子サポートを提供するため) ; そしてExpression
、型付きデリゲートにコンパイルできます-仕事は完了です。
私はデリゲートを使用してスレッドと通信します。
たとえば、ファイルをダウンロードするWinフォームアプリがあるとします。アプリは、ダウンロードを行うためにワーカースレッドを開始します(これにより、GUIがロックするのを防ぎます)。ワーカースレッドはデリゲートを使用してステータスメッセージ(ダウンロードの進行状況など)をメインプログラムに送り返すので、GUIはステータスバーを更新できます。
イベントハンドラー
メソッドパラメータでメソッドを渡すには
イベント、その他のエニッチ操作
遅延パラメーターの初期化!以前のすべての回答(戦略パターン、オブザーバーパターンなど)に加えて、デリゲートを使用すると、パラメーターの遅延初期化を処理できます。たとえば、かなり時間がかかり、特定のDownloadedObjectを返す関数Download()があるとします。このオブジェクトは、特定の条件に応じてストレージによって消費されます。通常、次のようにします。
storage.Store(conditions, Download(item))
ただし、デリゲート(より正確には、ラムダ)では、ストアの署名を変更して、ConditionとFunc <Item、DownloadedObject>を受け取り、次のように使用することで、次のことができます。
storage.Store(conditions, (item) => Download(item))
したがって、ストレージはデリゲートを必要な場合にのみ評価し、条件に応じてダウンロードを実行します。
デリゲートの使用
デリゲートは、参照によってメソッドを呼び出すために使用されます。例えば:
delegate void del_(int no1,int no2);
class Math
{
public static void add(int x,int y)
{
Console.WriteLine(x+y);
}
public static void sub(int x,int y)
{
Console.WriteLine(x-y);
}
}
class Program
{
static void Main(string[] args)
{
del_ d1 = new del_(Math.add);
d1(10, 20);
del_ d2 = new del_(Math.sub);
d2(20, 10);
Console.ReadKey();
}
}