確かFunc
に、特定のデリゲートの代わりに使用する実際の理由は、C#が個別に宣言されたデリゲートを完全に異なる型として扱うためです。
にもかかわらずFunc<int, bool>
とPredicate<int>
の両方が同一の引数や戻り値の型を持っている、彼らは代入互換性がありません。したがって、すべてのライブラリがデリゲートパターンごとに独自のデリゲートタイプを宣言した場合、ユーザーが「ブリッジング」デリゲートを挿入して変換を実行しない限り、それらのライブラリは相互運用できません。
// declare two delegate types, completely identical but different names:
public delegate void ExceptionHandler1(Exception x);
public delegate void ExceptionHandler2(Exception x);
// a method that is compatible with either of them:
public static void MyExceptionHandler(Exception x)
{
Console.WriteLine(x.Message);
}
static void Main(string[] args)
{
// can assign any method having the right pattern
ExceptionHandler1 x1 = MyExceptionHandler;
// and yet cannot assign a delegate with identical declaration!
ExceptionHandler2 x2 = x1; // error at compile time
}
マイクロソフトは、Funcの使用をすべてのユーザーに奨励することにより、互換性のないデリゲート型の問題が軽減されることを期待しています。全員のデリゲートは、パラメーター/戻り値のタイプに基づいて照合されるので、一緒にうまくプレイします。
Func
(およびAction
)がout
or ref
パラメータを持つことができないため、すべての問題を解決するわけではありませんが、それらはあまり一般的に使用されません。
更新:コメントでSvishは言う:
それでも、パラメータタイプをFuncからPredicateに切り替えてから戻しても、違いはないように見えますか?少なくとも問題なくコンパイルできます。
はい、Main
関数の最初の行のように、プログラムがデリゲートにメソッドを割り当てるだけである限り。コンパイラは、メソッドに転送する新しいデリゲートオブジェクトへのコードをサイレントに生成します。したがって、私のMain
関数では、問題を起こさずx1
にタイプに変更できますExceptionHandler2
。
ただし、2行目では、最初のデリゲートを別のデリゲートに割り当てようとしています。2番目のデリゲート型はパラメーターと戻り値の型がまったく同じであると考えていても、コンパイラーはエラーを出しますCS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
。
多分これはそれをより明確にするでしょう:
public static bool IsNegative(int x)
{
return x < 0;
}
static void Main(string[] args)
{
Predicate<int> p = IsNegative;
Func<int, bool> f = IsNegative;
p = f; // Not allowed
}
私の方法IsNegative
は、私が直接行う限り、p
およびf
変数に割り当てるのに最適です。しかし、それらの変数の1つを他の変数に割り当てることはできません。