(もちろん、問題から抜け出すには、単に と言ってTask.Run((Func<int>)MyIntReturningMethod)
ください。)
などとは一切関係ありませんTask
。
ここで注意すべき問題の 1 つは、非常に多くのオーバーロードが存在する場合、コンパイラエラー テキストが 1 つの "ペア" のオーバーロードだけに集中することです。それは紛らわしいです。その理由は、最適なオーバーロードを決定するアルゴリズムがすべてのオーバーロードを考慮し、そのアルゴリズムが最適なオーバーロードが見つからないと結論付けた場合、エラー テキストに対して特定のオーバーロードのペアを生成しないためです。関与してきました。
何が起こるかを理解するには、代わりにこの単純化されたバージョンを参照してください。
static class Program
{
static void Main()
{
Run(() => 5); // compiles, goes to generic overload
Run(M); // won't compile!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
static int M()
{
return 5;
}
}
ご覧のとおり、これには への参照はまったくありませんTask
が、それでも同じ問題が発生します。
無名関数の変換とメソッド グループの変換は (まだ) まったく同じではないことに注意してください。詳細はC# 言語仕様に記載されています。
ラムダ:
() => 5
実際にはSystem.Action
型に変換することさえできません。あなたがしようとすると:
Action myLittleVariable = () => 5;
エラー CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement で失敗します。したがって、ラムダで使用するオーバーロードは非常に明確です。
一方、メソッド グループ:
M
Func<int>
と の両方に変換可能Action
です。ステートメントのように、戻り値を取得しないことは完全に許可されていることに注意してください。
M(); // don't use return value
自体は有効です。
この種の答えは質問に答えますが、追加のポイントを作るために追加の例を挙げます. 例を考えてみましょう:
static class Program
{
static void Main()
{
Run(() => int.Parse("5")); // compiles!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
}
この最後の例では、ラムダは実際に両方のデリゲート型に変換可能です! (一般的なオーバーロードを削除してみてください。) ラムダ矢印の右側=>
は次の式です。
int.Parse("5")
これは、それ自体でステートメントとして有効です。ただし、この場合でも、オーバーロードの解決により、より適切なオーバーロードを見つけることができます。前述したように、C# の仕様を確認してください。
HansPassant と BlueRaja-DannyPflughoeft に触発された、最後の (私が思う) 例を 1 つ示します。
class Program
{
static void Main()
{
Run(M); // won't compile!
}
static void Run(Func<int> f)
{
}
static void Run(Func<FileStream> f)
{
}
static int M()
{
return 5;
}
}
この場合、 をint
5
に変換する方法はまったくないことに注意してくださいSystem.IO.FileStream
。それでもメソッド グループの変換は失敗します。これは、 が と の 2 つの通常のメソッドint f();
を持っているという事実に関連している可能性がFileStream f();
ありますf();
。戻り値の型は、C# のメソッドのシグネチャの一部ではありません。
Task
この問題が何であるかについて間違った印象を与える可能性があるため、回答で紹介することはまだ避けています。人々は を理解するのに苦労Task
しており、BCL では比較的新しいものです。
この答えは大きく進化しました。最終的に、これはスレッドFunc<T>
Func<IEnumerable<T>>
にあるのと同じ根本的な問題であることが判明しました。. Func<int>
andを使用した私の例は、Func<FileStream>
ほぼ同じように明確です。Eric Lippert は、別のスレッドで適切な回答を提供しています。