为什么我不能在Tuple.Create中使用lambda表达式
本文关键字:lambda 表达式 Create 不能 Tuple 为什么 | 更新日期: 2023-09-27 18:17:54
我知道编译器可以将lambda表达式强制转换为Predicate。
例如:Predicate<int> p = x => true;
是好的。
但是当我想创建一个包含谓词的元组时。我试着这样做(简化版):
Tuple<Predicate<int>> t;
t = Tuple.Create(x => true);
,我得到了编译错误:
方法'System.Tuple.Create(T1)'的类型参数不能从用法中推断出来。尝试显式指定类型参数。
我的问题是这是一个错误,这里的歧义在哪里?
(我知道我可以通过cast: 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)的方法调用,类型推断的任务为查找每个类型参数的唯一类型参数S1…SnX1…Xn,使调用M(E1…Em)生效
现在我们开始:
7.5.2.1第一阶段:对于每个方法参数Ei:
如果Ei是匿名函数,则显式参数类型推断(§7.5.2.7)由Ei到Ti
我们来看看显式参数类型推断是怎么做的:
7.5.2.7显式参数类型推断
从表达式E到类型T进行显式参数类型推断方法:
·如果E是一个显式类型匿名函数
您的匿名函数不是显式类型,因此编译器无法从参数类型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>
?没有足够的信息来确定,除非在编译器设计不检查的位置。