74

今日、私はこれを宣言することを考えていました:

private delegate double ChangeListAction(string param1, int number);

しかし、なぜこれを使用しないのですか:

private Func<string, int, double> ChangeListAction;

または、ChangeListAction使用できる戻り値がない場合:

private Action<string,int> ChangeListAction;

delegateでは、キーワードでデリゲートを宣言する利点はどこにあるのでしょうか?

.NET 1.1 が原因で、.NET 2.0 が登場Action<T>し、.NET 3.5 が登場したためFunc<T>ですか?

4

8 に答える 8

62

利点は明快さです。型に明示的な名前を付けることで、それが何をするのかがより明確になります。

コードを書くときにも役立ちます。次のようなエラー:

cannot convert from Func<string, int, double> to Func<string, int, int, double>

次のように言うよりも役に立ちません。

cannot convert from CreateListAction to UpdateListAction

また、2 つの異なるデリゲートがあり、どちらも同じ型のパラメーターを受け取りますが、概念的にはまったく異なる 2 つのことを行う場合、コンパイラーは、意図したところで一方を誤って使用しないようにすることができます。

于 2010-12-19T11:02:48.287 に答える
10

デリゲートを明示的に宣言すると、一部の型チェックに役立ちます。コンパイラは、変数に割り当てられたデリゲートが ChangeListAction として使用されることを意図しており、署名と互換性のあるランダムなアクションではないことを確認できます。

ただし、独自のデリゲートを宣言することの真の価値は、それがセマンティックな意味を与えることです。コードを読んだ人は、デリゲートが何をしているのかをその名前で知ることができます。3 つの int フィールドを持つクラスがあり、代わりに 3 つの int 要素の配列を宣言したとします。配列は同じことを行うことができますが、フィールドの名前は、開発者にとって有用なセマンティック情報をもたらします。

LINQ のような汎用ライブラリを設計する場合は、Func、Predicate、および Action デリゲートを使用する必要があります。この場合、デリゲートには、実行してアクションを実行するか、述語として使用されるという事実以外に、定義済みのセマンティクスがありません。

余談ですが、タプルと匿名型と独自のクラスを宣言することには、同様のトレードオフの問題があります。タプルにすべてを貼り付けることができますが、プロパティは Item1、Item2 だけであり、タイプの使用については何もわかりません。

于 2010-12-19T11:06:13.160 に答える
8

一部の回答では、勝利は明確であると述べられているため、タイプに名前を付けると、API のユーザーにとって理解しやすくなります。ほとんどの場合、パブリック API のデリゲート型を宣言しますが、Func<?,?>内部で使用しても問題ありません。

他の回答で言及されていないデリゲート型を宣言することの大きな利点の1つは、型に名前を付けるだけでなく、実際にパラメーターにも名前を付けることができることです。これにより、使いやすさが大幅に向上します。

于 2010-12-19T11:10:48.663 に答える
7

デリゲートのみを使用できる特別なユースケースを見つけました。

public delegate bool WndEnumProc(IntPtr hwnd, IntPtr lParam);
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);

Func/Action を使用しても機能しません: 'Namespace.Class.WndEnumProc' is a 'field' but is used like a 'type':

public Func<IntPtr, IntPtr, bool> WndEnumProc;
[DllImport("User32.dll")]
public static extern bool EnumWindows(WndEnumProc lpEnumFunc, IntPtr lParam);

System.Runtime.InteropServices.DllImportAttribute次のコードはコンパイルされますが、ジェネリック型のマーシャリングをサポートしていないため、実行時に例外がスローされます。

[DllImport("User32.dll")]
public static extern bool EnumWindows(Func<IntPtr, IntPtr, bool> lpEnumFunc, IntPtr lParam);

この例をすべての人に示すために提示します。デリゲートが唯一の選択肢である場合もあります。そして、これはあなたの質問に対する合理的な答えですwhy not use Action<T>/Func<T> ?

于 2014-12-05T03:56:00.613 に答える
4

Func/Action であまりにも多くのパラメーターを取得し始めたら、デリゲートを明示的に宣言します。そうしないと、「2 番目の int は何を意味するのか?」と振り返る必要があります。

于 2010-12-19T11:07:47.140 に答える
2

より優れたより精巧な回答については、@nawfal を参照してください。もっとシンプルにしようと思います。

クラスのメンバーを宣言しているので、デリゲートに固執する必要があります。Usingdelegateは、より説明的で構造的です。

Action/Func型は受け渡し用に作成されているため、パラメーターやローカル変数として使用する必要があります。

そして実際には、それらの両方がDelegateクラスを継承しています。Action と Func はジェネリック型であり、異なるパラメーター型を持つデリゲートの作成を簡素化します。そして、delegate キーワードは、実際には、1 つの宣言で Delegate から継承する新しいクラス全体を作成します。

于 2016-10-20T08:04:19.070 に答える
1

MSDNが言ったように、それFunc<>自体が事前定義されてDelegateいます。初めて、私はこのことについて混乱しました。実験の後、私の理解はかなり明確になりました。通常、C# では、

TypeへのポインタとしてInstance

同じ概念が適用されます

DelegateへのポインタとしてMethod

これらのモノとの違いはDelegate、OOP の概念を持っていないことですInheritance。このことをより明確にするために、私は実験を行いました

public delegate string CustomDelegate(string a);

// Func<> is a delegate itself, BUILD-IN delegate
//==========
// Short Version Anonymous Function
Func<string, string> fShort = a => "ttt";
//----------
// Long Version Anonymous Function
Func<string, string> fLong = delegate(string a)
{
  return "ttt";
};
//----------
MyDelegate customDlg;
Func<string, string> fAssign;
// if we do the thing like this we get the compilation error!!
// because fAssign is not the same KIND as customDlg
//fAssign = customDlg;

フレームワーク (LINQ など) の多くの組み込みメソッドは、Func<>デリゲートのパラメーターを受け取ります。この方法でできることは、

Declareタイプのデリゲートをカスタム デリゲートFunc<>ではなく関数に渡します。Define

たとえば、上記のコードからさらにコードを追加します

string[] strList = { "abc", "abcd", "abcdef" };
strList.Select(fAssign); // is valid
//strList.Select(customDlg); // Compilation Error!!
于 2016-08-18T10:30:40.770 に答える