確かに、特定のデリゲートの代わりに使用する実際の理由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 を使用するよう奨励することで、Microsoft は互換性のないデリゲート型の問題が軽減されることを期待しています。パラメーター/戻り値の型に基づいて一致するだけなので、全員のデリゲートは一緒にうまく機能します。
Func
(and Action
) はout
orパラメーターを持つことができないため、すべての問題を解決できるわけではありませんがref
、これらはあまり一般的に使用されていません。
更新:コメントで Svish は言います:
それでも、パラメーターの型を Func から Predicate に切り替えたり、元に戻したりしても、違いはないように見えますか? 少なくとも問題なくコンパイルできます。
Main
はい、私の関数の最初の行のように、プログラムがデリゲートにメソッドを割り当てるだけである限り。コンパイラは、メソッドに転送する新しいデリゲート オブジェクトのコードを暗黙的に生成します。したがって、私のMain
関数では、問題を引き起こすことなくx1
型に変更できました。ExceptionHandler2
ただし、2 行目では、最初のデリゲートを別のデリゲートに割り当てようとしています。2 番目のデリゲート型のパラメーターと戻り値の型がまったく同じであるにもかかわらず、コンパイラは error を返します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
、まったく問題ありません。しかし、これらの変数の 1 つを別の変数に割り当てることはできません。p
f