7

私は最近、デリゲートをいじり、ラムダを含むFunc<T, TResult>さまざまなインスタンスを返すメソッドを作成していますFunc<T, TResult>が、私が思いつくのに苦労したのは、戻りたい(またはそのようなインスタンスを作成したい)理由についての良い現実世界のアイデアです.

MSDNには、次のことを行う例があります...

Func<string, string> convertMethod = UppercaseString;
private static string UppercaseString(string inputString)
{
    return inputString.ToUpper();
}

見た目はきれいで興味深いコンセプトですが、そのようなコードが提供する利点がわかりません。

では、ここで誰かが使用しなければならなかった実際の例Func<T, TResult>と、一般的にこのデリゲートを使用する理由を教えてください。

4

8 に答える 8

12

あなたが本当に求めているのが、一般的にデリゲートを持っている理由である場合:

  • イベントを使用したことがある場合は、デリゲートを使用しています
  • LINQ を使用したことがある場合は、デリゲートを使用したことになります (技術的には、IQueryableプロバイダーでは式を使用しましたが、LINQ-to-Objects ではデリゲートを使用しました)。

デリゲートは、独自の動作を別のオブジェクトに注入する方法を提供します。最も一般的な使用法はイベントです。オブジェクトはイベントを公開し、そのイベントが発生したときに呼び出される関数 (匿名または非匿名) を提供します。

(および同様の) デリゲートがある理由を尋ねている場合は、Func<T, TResult>主な理由が 2 つあります。

  1. コードで特定のデリゲートが必要な場合、ユーザーは独自の単純なデリゲート型を宣言する必要がありました。Action<>およびFunc<>デリゲートはすべてのケースに対応できるわけではありませんが、簡単に提供でき、カスタムデリゲートが必要な多くのケースに対応できます。
  2. さらに重要なことに、Func<T, TResult>デリゲートは述語を定義するために LINQ-to-Objects で広く使用されています。より具体的には、Func<T, bool>. IEnumerable<T>これにより、厳密に型指定された an のメンバーを受け取り、ラムダ関数または通常の関数を使用してブール値を返す述語を定義し、その述語を LINQ-to-Objects に渡すことができます。
于 2011-06-01T03:06:42.003 に答える
4

LINQ でよく使用します。たとえば、リスト内のすべての数値を 2 倍にするには、次のようにします。

myList.Select(x => x * 2);

それはFunc<TIn, TOut>. 簡潔なコードを作成するときに非常に便利です。実際の例は、私が作成した多くのタワー ディフェンス ゲームの 1 つです。1 行を使用して、タワーに最も近い敵を計算しました。

enemies.Select(x => tower.Location.DistanceTo(x.Location)).OrderBy(x => x).FirstOrDefault();
于 2011-06-01T03:06:23.500 に答える
3

良い例は遅延初期化だと思います。

var value = new Lazy<int>(() => ExpensiveOperation()); // Takes Func<T>
于 2011-06-01T03:07:40.130 に答える
3

関数ポインターの必要性の標準的な例は、比較関数がソートルーチンに渡されることです。異なるソート キーを使用するには、比較関数用のラムダを作成し、それをソート関数に渡します。

または、単純な実世界の例:

IEnumerable<Person> FindByLastName(string lastName)
{
    return Customers.Where(cust => cust.LastName == lastName);
}

この例では、cust => cust.LastName == lastNameは単なるラムダではありませんが、lastNameパラメーターをキャプチャしてクロージャーを作成します。つまり、呼び出されるたびに異なる関数を作成FindByLastNameします。

于 2011-06-01T03:12:52.427 に答える
2

デリゲート (およびその他のFunc<T>オーバーロード) は、C# で抽象化を記述するための新しい方法を提供します。オプションのいくつかを示すために、代わりにデリゲートを使用して記述できるいくつかの C# 言語構造を次に示します。

Thread.Lock(obj, () => { 
    // Safely access 'obj' here
});

Enumerable.ForEach(collection, element => {
    // Process 'element'
});

Exceptions.Try(() => { 
    // Try block
}).With((IOException e) => {
    // Handle IO exceptions
});

これらは非常に原始的であるため、言語構造を持つことは良いことです。ただし、Funcラムダ式が非常に多くの表現力を追加することを示しています。並列ループ(.NET 4.0 を使用)などの新しい構造を作成できます。

Parallel.ForEach(collection, element => {
    // Process 'element'
});
于 2011-06-01T03:14:30.243 に答える
1

まず第一に、Func<T>これはクラスではなくデリゲートです。

基本的に、独自のデリゲートを宣言したくない場合は、メソッド引数またはデリゲート型のプロパティが必要なときにいつでも使用できます。

于 2011-06-01T03:10:02.423 に答える
1

Funct<T>LINQ、モッキング ツール、依存性注入コンテナーなどの多くのフレームワークに組み込まれているという事実に加えて、 の優れた用途の 1 つは、それを使用してデリゲート ベースの factoryを作成することです。

于 2011-06-01T03:17:38.700 に答える
0

最近、メソッドを呼び出す外部プログラムの動作を変更できるようにしたいと考えました。

私の方法自体は、ファイルを XLS から XML に変換するだけです。ただし、必要に応じて、xml タグとして書き込む前に各 xls セルに適用する任意の数の変換を呼び出しコードで指定できるようにする必要がありました。たとえば、「,」の小数点記号を「.」に変換したり、3 桁ごとの区切り文字を抑制したりします (変換はすべて文字列の置換でした)。

次に、呼び出し元コードは、キーがパターンで、値がこのパターンの置換文字列であるディクショナリに任意の数のエントリを追加する必要がありました。私のメソッドは辞書をループし、Func<string,string>エントリごとに新しいものを作成します。次に、セルごとFunc<string,string>に が順番に適用されます。

于 2011-06-01T08:13:58.820 に答える