我进行了以下推理测试:
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#可以从Func<T1, T2>
中的方法返回值推断ConsumeFunc1Func2
的类型参数,但无法推断Func<T, T>
中ConsumeFunc2c
的类型{1}}。
此问题类似于T of Func<S, T> is inferred from output of lambda expression only when S and T are different?问题,但我们使用非通用方法组而不是具有未知参数类型的lambdas。
Why can't C# infer type from this seemingly simple, obvious case问题回答了一些问题“为什么非模糊的非泛型方法不足以进行推理?”和“为什么参数类型和推理的返回值类型之间存在差异?”。
问题:
为什么C#编译器可以使用返回值的类型推断出Func<T>
的类型,但却未能在Func<T, T>
情况下看到成功?
为什么C#编译器可以从T1
中的Func<T1, T2>
推断出Func<T1>
的{{1}}类型参数,但无法推断出ConsumeFunc1Func2
类型参数{ {1}} T
中的{1}}似乎更容易?
答案 0 :(得分:1)
未检查方法参数。
根据建议,在ConsumeFunc1Func2中,编译器仅从返回值推断。 在ConsumeFunc2c中,未检查TakeAndGiveInt签名以查看其方法参数类型是否实际上与方法返回类型相同的类型原因...方法参数未被检查!
答案 1 :(得分:1)
通常,方法名称不会唯一标识可以为其分配方法组的唯一类型Action<T>
。例如,即使只有Fred
的一个重载并且只需要一个Cat
参数,该重载不仅可以分配给Action<Cat>
,还可以分配给其他类型的Action<Mammal>
。 {1}},Action<Animal>
或Action<Object>
。虽然在某些情况下,一种类型的替代在各方面都优于任何替代方案,但情况并非总是如此。定义语言要求指定委托类型比让编译器试图“猜测”更清晰,特别是因为编译器猜测会意味着许多不应该破坏变化的东西(例如添加方法重载可能会使类型推断变得模糊不清(。)