首页 > 解决方案 > 为什么我必须在 lambda 表达式中使用 out/ref 显式定义所有类型?

问题描述

如果我有一个用out这样的关键字定义的委托:

delegate int D<TResult, TArgument>(TArgument argument, out TResult result);

我想用一个 lambda 表达式来设置它,它必须是这样的:

        D<int, int> d = (int arg, out int rst) =>{...} //correct

以下两种说法是错误的:

        D<int, int> d1 = ( arg, out rst) => {...} //CS2046

        D<int, int> d2 = (arg, out int rst) => {...} //CS0748

所以我的问题是:为什么 C# 会这样设计?我了解您必须声明out才能清楚并能够超载。但很明显,rst而且arg必须如此int。为什么我必须定义所有这些?CS0748告诉我不要这样做,但不知道为什么。

在我看来,这是应该的。是否有任何异常可能导致问题?

D<int, int> d1 = ( arg, out rst) => {...} ////won't compile

更新

看起来这个问题仍在 C# 设计组中讨论。在官方 C# 语言设计 repo #338中有很多关于这个未解决问题的建议。

标签: c#lambda

解决方案


似乎 C# 语言的设计者决定严格来说可以有两种匿名函数签名——它们被定义为显式匿名函数签名隐式匿名函数签名

显式匿名函数签名是一个相当标准的参数列表——在括号之间()并用逗号分隔,每个参数定义由一个可选的修饰符(outref)、一个类型和一个标识符组成。

隐式匿名函数签名是一个非常简单的参数列表 - 在括号之间()并用逗号分隔,每个参数定义仅包含一个标识符。

你不能在两种形式之间混搭,你必须选择其中一种。这可能使解析更简单,并使类型推断成为一个关闭/开启的概念,而不是“半开”的概念(这就是CS0748真正的意思)。

它当然可以让他们通过使用一种或另一种类型的签名来讨论 lambda,从而使语言中的其他规则更容易指定。

因此,如果您需要包含修饰符 ( out),您将别无选择 - 您必须使用显式匿名功能签名


来自 C# 规范,版本 5:

lambda 表达式

  • 匿名函数签名 => 匿名函数体

匿名方法表达式

  • delegate 显式匿名功能签名选择

匿名函数签名

  • 显式匿名函数签名

  • 隐式匿名函数签名

显式匿名函数签名

  • ( 显式匿名函数参数列表选项 )

显式匿名函数参数列表

  • 显式匿名函数参数

  • 显式匿名函数参数列表 , 显式匿名函数参数

显式匿名函数参数

  • 匿名函数参数修饰符opt 类型 标识符

匿名函数参数修饰符

  • ref

  • out

隐式匿名函数签名

  • ( 隐式匿名函数参数列表选项 )

  • 隐式匿名函数参数

隐式匿名函数参数列表

  • 隐式匿名函数参数

  • 隐式匿名函数参数列表 , 隐式匿名函数参数

隐式匿名函数参数

  • 标识符

推荐阅读