C# 为什么我能';不要在元组中使用lambda表达式。是否创建?

C# 为什么我能';不要在元组中使用lambda表达式。是否创建?,c#,lambda,delegates,tuples,predicate,C#,Lambda,Delegates,Tuples,Predicate,我知道编译器可以从lambda表达式转换为谓词 例如: Predicate<int> p = x => true; 谓词p=x=>true; 这很好 但是当我想创建一个包含谓词的元组时。 我尝试过这样做(简化版): 元组t; t=Tuple.Create(x=>true); 我得到了编译错误: 无法从用法推断方法“System.Tuple.Create(T1)”的类型参数。尝试显式指定类型参数 我的问题是这是什么错误,这里的模糊性在哪里 (我知道我可以通过强制转换来修复它

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

例如:

Predicate<int> p = x => true;
谓词p=x=>true;
这很好

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

元组t;
t=Tuple.Create(x=>true);
我得到了编译错误:

无法从用法推断方法“System.Tuple.Create(T1)”的类型参数。尝试显式指定类型参数

我的问题是这是什么错误,这里的模糊性在哪里

(我知道我可以通过强制转换来修复它:
t=Tuple.Create((谓词)(x=>true));
但我想了解为什么第一种方法不好,而且我不想为了省去打字而进行转换:)

这里的歧义在哪里

这里的不明确之处在于编译器没有试图推断传递给
Tuple.Create的lambda表达式,该表达式基于已声明所需类型的左侧。发生的情况是,类型推断算法启动(无论您声明变量的类型如何),并且无法找到与lambda表达式相匹配的匹配项,因为它没有足够的信息

通过声明元组的类型并显式告诉编译器如何推断lambda表达式,可以很容易地解决这一问题:

t = Tuple.Create<Predicate<int>>(x => true);
t=Tuple.Create(x=>true);
如果您想进入类型推断算法并了解它失败的原因:

鉴于:

Tr M<X1…Xn>(T1 x1 … Tm xm)
trm(T1-x1…Tm-xm)
对于形式为M(E1…Em)的方法调用,类型推断的任务是 为每个类型参数查找唯一的类型参数S1…Sn X1…Xn,以便调用M(E1…Em)变得有效

现在我们开始:

7.5.2.1第一阶段:

对于每个方法参数Ei:

如果Ei是一个匿名函数,显式参数类型推断 (§7.5.2.7)从Ei到Ti

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

7.5.2.7明确的参数类型推断

从表达式E到类型T进行显式参数类型推断,如下所示 方式:

·如果E是显式类型化的匿名函数 参数类型U1…Uk和T是委托类型或表达式树类型 对于参数类型V1…Vk,则每个Ui都有一个精确的推断 (§7.5.2.8)从Ui到相应的Vi


匿名函数不是显式类型,因此编译器无法从参数类型Ui..Uk精确推断
元组的正确重载。Create

元组。Create
方法采用泛型类型参数。当您调用它时,编译器通常可以猜测这些类型是什么。然而,对于谓词,它无法理解它。一些解决办法是:

Predicate<int> p = x => true;
var t = Tuple.Create(p);
谓词p=x=>true;
var t=Tuple.Create(p);
或者我建议您只指定类型参数:

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

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

C语言的设计是为了

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


现在,考虑到这一点,编译器应该如何确定
Tuple.Create(x=>true)
应该将
x=>true
视为
谓词
,而不是
Func
?没有足够的信息来确定这一点,除非在编译器按设计不检查的位置。

Tuple.Create与前面声明的
t
无关。所以编译器无法推断x的类型。
t=Tuple.Create(x=>true)将起作用。您必须以某种方式指定类型。Just
x=>true
是不明确的定义。或者编写自己的工厂方法:
Tuple CreateTuple(谓词){return Tuple.Create(谓词);}
只是为了让您清楚。这将工作
t=Tuple.Create((谓词)(x=>true))。为什么?因为您已将
x=>true
转换为已知类型
谓词
,并且您必须知道
x=>true
对编译器可能有数千种意义。无论如何,因为
Tuple.Create
是泛型类型,所以您可以指定类型而不是强制转换,这更好,并在答案中进行了解释。您的第一个示例仍然无法编译;我想你的意思是
Tuple.Create(p)
谢谢你的详细解释。它帮助我更好地理解它(虽然它对我来说仍然有点模糊,不是你的错,我需要更多地了解它)。@Erez它会随着时间而来。很高兴我能帮忙:)
t = Tuple.Create(x => true);