[英]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);
我收到了编译错误:
无法从用法推断出方法'System.Tuple.Create(T1)'的类型参数。 尝试显式指定类型参数。
我的问题是这是一个错误,这里的歧义在哪里?
(我知道我可以通过强制转换来修复它: t = Tuple.Create((Predicate<int>)(x => true));
但我想理解为什么第一种方式不好,而且我也不想做铸造以节省输入:)
这里含糊不清哪里?
这里的歧义是编译器不会尝试根据已经声明所需类型的左侧推断传递给Tuple.Create
的lambda表达式。 会发生什么样的类型推断算法 (无论你声明变量的类型),并且找不到与lambda表达式匹配的合适匹配,因为它没有足够的信息。
通过声明元组的类型并明确告诉编译器如何推断lambda表达式,可以很容易地解决这个问题:
t = Tuple.Create<Predicate<int>>(x => true);
如果您想进入类型推断算法并查看它失败的原因:
鉴于:
Tr M<X1…Xn>(T1 x1 … Tm xm)
通过形式M(E1 ... Em)的方法调用,类型推断的任务是为每个类型参数X1 ... Xn找到唯一类型参数S1 ... Sn,使得调用M(E1 ... Em)变为有效。
现在我们开始:
7.5.2.1第一阶段:
对于每个方法参数Ei:
如果Ei是匿名函数, 则从Ei到Ti进行显式参数类型推断(第7.5.2.7节)
所以我们看一下显式参数类型推断的作用:
7.5.2.7显式参数类型推断
通过以下方式从表达式E到类型T进行显式参数类型推断:
·如果E是具有参数类型U1的明确类型的匿名函数 ... Uk和T是具有参数类型V1 ... Vk的委托类型或表达式树类型,则对于每个Ui,从Ui到Ui进行精确推断(第7.5.2.8节)相应的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>
? 没有足够的信息来确定,除了在设计编译器不检查的位置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.