私は、次の推論のテストを行った:C#はジェネリック型の引数型を非ジェネリックな静的なメソッドのシグネチャから推測できないのはなぜですか?
static class InferenceTest {
static void TakeInt(int a) { }
static int GiveInt() { return 0; }
static int TakeAndGiveInt(int a) { return 0; }
static void ConsumeAction1<T>(Action<T> a) { }
static void ConsumeFunc1<T>(Func<T> f) { }
static void ConsumeFunc2a<T1, T2>(Func<T1, T2> f) { }
static void ConsumeFunc2b<T>(Func<int, T> f) { }
static void ConsumeFunc2c<T>(Func<T, T> f) { }
static void ConsumeFunc1Func2<T1, T2>(Func<T1> f1, Func<T1, T2> f2) { }
static void Main() {
ConsumeAction1(TakeInt); //error
ConsumeFunc1(GiveInt); //ok
ConsumeFunc2a(TakeAndGiveInt); //error
ConsumeFunc2b(TakeAndGiveInt); //ok
ConsumeFunc2c(TakeAndGiveInt); //error
ConsumeFunc1Func2(GiveInt, TakeAndGiveInt); //ok
}
}
結果は、C#コンパイラは、非ジェネリックメソッドグループからデリゲート関数のパラメータのためのジェネリック型引数を推論することができないことを示唆しているように見えます。最も私を困惑何
は、C#はConsumeFunc1Func2
にメソッドの戻り値からFunc<T1, T2>
ための型引数を推論することができているということですが、ConsumeFunc2c
にFunc<T, T>
のための型を推論することができません。
この質問はT of Func<S, T> is inferred from output of lambda expression only when S and T are different?の質問に似ていますが、パラメータタイプが不明なラムダの代わりに非ジェネリックメソッドグループがあります。
Why can't C# infer type from this seemingly simple, obvious case質問ソートの回答質問「非あいまいではない非ジェネリックメソッドが推論には不十分なのはなぜですか?」 "なぜ引数型と推論の戻り値型が異なるのですか?"
質問:
なぜC#コンパイラは、戻り値の型を使用してFunc<T>
の種類を推測することができますが、Func<T, T>
場合の成功を見ることができませんか?
なぜC#コンパイラはConsumeFunc1Func2
でFunc<T1>
からFunc<T1, T2>
ためT1
型引数を推論することができますが、より簡単であるように思われConsumeFunc2c
自体からFunc<T, T>
ためT
型引数を推論することはできませんか?
ConsumeFunc1Func2では、コンパイルは依然としてパラメータ型ではなく戻り値からのみ推測されます。 T1はGiveIntの戻り値から解決され、T2はTakeAndGiveIntの戻り値から解決されます。したがって、ConsumeFunc1Func2のケースで追加された謎はありません。 – Baldrick
私はC#4.0仕様のセクション7.5.2をよく読んでいます。これは非常に読みやすく、型推論のさまざまな段階、およびそれらがメソッドグループにどのように関係しているかを記述します。 – Baldrick
'ConsumeFunc2b'は' Func , T> 'の戻り値の型' T'を 'TakeAndGiveInt'から解決できることを示しています。しかし、 '?'も 'ConsumeFunc2c'の' Func 'の場合のように' T'であるとき、コンパイラはパラメータ 'T'を既に忘れていると思われます。 'ConsumeFunc1Func2'の成功とはまったく異なります。 –