【问题标题】:Why I can't use lambda expression inside Tuple.Create?为什么我不能在 Tuple.Create 中使用 lambda 表达式?
【发布时间】:2015-10-15 10:34:47
【问题描述】:

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

例如:

Predicate<int> p = x => true;

很好。

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

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

我得到了编译错误:

方法“System.Tuple.Create(T1)”的类型参数无法从用法中推断出来。尝试明确指定类型参数。

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

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

【问题讨论】:

  • Tuple.Create 与前面声明的 t 无关。所以编译器无法推断 x 的类型。
  • t = Tuple.Create&lt;Predicate&lt;int&gt;&gt;(x =&gt; true); 会工作。您必须以某种方式指定类型。只是x =&gt; true 是模棱两可的定义。
  • 或者自己写工厂方法:Tuple&lt;Predicate&lt;int&gt;&gt; CreateTuple(Predicate&lt;int&gt; predicate) { return Tuple.Create(predicate); }
  • 只是为了让你清楚。这将工作t = Tuple.Create((Predicate&lt;int&gt;) (x =&gt; true));。为什么?因为您已将x =&gt; true 转换为已知类型Predicate&lt;int&gt;,并且您必须知道x =&gt; true 对编译器有数千种含义。无论如何,因为Tuple.Create 是通用类型,您可以指定类型而不是强制转换,这更好并在答案中进行了解释。

标签: c# lambda delegates tuples predicate


【解决方案1】:

这里的歧义在哪里?

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

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

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

如果你想进入类型推断算法并看看它失败的原因:

给定:

Tr M<X1…Xn>(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 到 Tuple.Create 的正确重载进行精确推断。

【讨论】:

  • 感谢您的详细解释。它帮助我更好地理解它,(虽然它对我来说仍然有点模糊,不是你的错,我需要更多地了解它)。
  • @Erez 它会随着时间的推移而出现。很高兴我能帮忙:)
【解决方案2】:

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

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

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

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

【讨论】:

  • 您的第一个示例仍然无法编译;我想你的意思是Tuple.Create(p)
【解决方案3】:

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

C# 语言被设计成在

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

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

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

【讨论】:

    猜你喜欢
    • 2023-04-03
    • 2023-03-03
    • 1970-01-01
    • 2015-12-09
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多