为什么我不能在 Tuple.Create 中使用 lambda 表达式?

Why I can't use lambda expression inside Tuple.Create?

我知道编译器可以从 lambda 表达式转换为 Predicate。

例如:

Predicate<int> p = x => true;

很好。

但是当我想创建一个包含谓词的元组时。 我试过这样做(简化版):

Tuple<Predicate<int>> t;
t = Tuple.Create(x => true);

我得到了编译错误:

The type arguments for method 'System.Tuple.Create(T1)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

我的问题是这是什么错误,这里的歧义在哪里?

(我知道我可以通过转换来修复它:t = Tuple.Create((Predicate<int>)(x => true)); 但我想了解为什么第一种方法不好,而且我不想进行转换以节省输入:)

where is the ambiguity here?

这里的歧义是编译器不会尝试根据已经声明所需类型的左侧来推断传递给 Tuple.Create 的 lambda 表达式。发生的事情是 类型推断算法 启动(无论您声明变量的类型如何),并且由于没有足够的信息而无法找到与您的 lambda 表达式相匹配的匹配项。

这可以通过声明元组的类型并明确告诉编译器如何推断 lambda 表达式来轻松解决:

t = Tuple.Create<Predicate<int>>(x => true);

如果您想了解类型推断算法并了解它失败的原因:

鉴于:

Tr M<X1…Xn>(T1 x1 … Tm xm)

With a method call of the form M(E1 …Em) the task of type inference is to find unique type arguments S1…Sn for each of the type parameters X1…Xn so that the call M(E1…Em) becomes valid.

现在我们开始:

7.5.2.1 The first phase:

For each of the method arguments Ei:

If Ei is an anonymous function, an explicit parameter type inference (§7.5.2.7) is made from Ei to Ti

所以我们看看显式参数类型推断的作用:

7.5.2.7 Explicit parameter type inferences

An explicit parameter type inference is made from an expression E to a type T in the following way:

· If E is an explicitly typed anonymous function with parameter types U1…Uk and T is a delegate type or expression tree type with parameter types V1…Vk then for each Ui an exact inference (§7.5.2.8) is made from Ui to the corresponding Vi.

您的匿名函数不是显式类型,因此编译器无法根据参数类型 Ui..Uk 进行精确推断以正确重载 Tuple.Create.

Tuple.Create 方法采用泛型类型参数。编译器通常可以在您调用它时猜测这些类型是什么。但是对于谓词,它无法弄清楚。一些解决方案是:

Predicate<int> p = x => true;
var t = Tuple.Create(p);

或者我建议你只指定类型参数:

var t = Tuple.Create<Predicate<int>>(x => true);

给出与现有答案略有不同的观点:

C# 语言的设计使得在

t = Tuple.Create(x => true);

Tuple.Create(x => true) 的类型不依赖于 t。这使得解析 C# 更容易,更容易推理 C# 代码,更容易为无效的 C# 代码实现正确的错误消息。

现在,鉴于此,编译器应如何确定 Tuple.Create(x => true) 应将 x => true 视为 Predicate<int>,而不是 Func<int, bool>?没有足够的信息来确定这一点,除了编译器在设计上不检查的位置。