C#7元组和lambda

Ras*_*ast 56 c# lambda tuples c#-7.0

使用新的c#7元组语法,是否可以指定一个带有元组作为参数的lambda并在lambda中使用解压缩的值?

例:

var list = new List<(int,int)>();
Run Code Online (Sandbox Code Playgroud)

在lambda中使用元组的常规方法:

list.Select(value => value.Item1*2 + value.Item2/2);
Run Code Online (Sandbox Code Playgroud)

我期待一些新的糖可以避免.Item1 .Item2,例如:

list.Select((x,y) => x*2 + y/2);
Run Code Online (Sandbox Code Playgroud)

最后一行不起作用,因为它被视为lambda的两个参数.我不确定是否有办法实际做到这一点.

编辑:

我尝试在lambda定义中进行双重注射,但它不起作用((x,y)) => ...,并且尝试可能是愚蠢的,但是双括号实际上在这里工作:

list.Add((1,2));
Run Code Online (Sandbox Code Playgroud)

另外,我的问题并不是关于避免丑陋的默认名称.Item .Item2,而是关于实际解压缩lambda中的元组(也许是为什么它没有实现或不可能).如果您来这里寻找默认名称的解决方案,请阅读Sergey Berezovskiy的回答.

编辑2:

刚想到一个更通用的用例:是否有可能(或者为什么不)将"解构"传递给方法的元组?像这样:

void Foo((int,int)(x,y)) { x+y; }
Run Code Online (Sandbox Code Playgroud)

而不是这个:

void Foo((int x,int y) value) { value.x+value.y }
Run Code Online (Sandbox Code Playgroud)

Dav*_*rno 34

正如您所观察到的,对于:

var list = new List<(int,int)>();
Run Code Online (Sandbox Code Playgroud)

人们至少希望能够做到以下几点:

list.Select((x,y) => x*2 + y/2);
Run Code Online (Sandbox Code Playgroud)

但是C#7编译器(尚未)支持这一点.希望糖能够满足以下要求是合理的:

void Foo(int x, int y) => ...

Foo(list[0]);
Run Code Online (Sandbox Code Playgroud)

与编译器转换Foo(list[0]);Foo(list[0].Item1, list[0].Item2);自动.

目前这两种情况都不可能.然而,问题,提议:lambda参数列表中的元组解构,存在dotnet/csharplang于GitHub 上的repo中,要求语言团队将这些特性考虑为未来版本的C#.如果您也希望看到支持,请将您的声音添加到该主题.


Ser*_*kiy 28

您应该指定元组属性的名称(嗯,ValueTuple有字段),否则将使用默认名称,如您所见:

var list = new List<(int x, int y)>();
Run Code Online (Sandbox Code Playgroud)

现在元组已经很好地命名了你可以使用的字段

list.Select(t => t.x * 2 + t.y / 2)
Run Code Online (Sandbox Code Playgroud)

不要忘记从NuGet 添加System.ValueTuple包,并记住ValueTuples是可变结构.


更新:解构当前仅表示为对现有变量(解构结构赋值)或新创建的局部变量(解构 - 声明)的赋值.适用的功能成员选择算法与以前相同:

参数列表中的每个参数对应于§7.5.1.1中描述的函数成员声明中的参数,并且无参数对应的任何参数都是可选参数.

元组变量是一个参数.它不能对应于方法的形式参数列表中的几个参数.

  • @Peter Duniho这只是我的好奇心.在这种情况下,我认为解构或类似的东西可能有用. (2认同)

Jul*_*eur 8

C#7.0中的解构支持三种形式:

  • 解构 - 声明(如(var x, var y) = e;),
  • 解构赋值(如(x, y) = e;),
  • 和解构 - foreach(喜欢foreach(var(x, y) in e) ...).

考虑了其他情况,但可能会降低效用,我们无法在C#7.0时间范围内完成它们.let子句(let (x, y) = e ...)和lambdas中的解构似乎是未来扩展的良好候选者.

后者正在https://github.com/dotnet/csharplang/issues/258中讨论

请在那里表达您的反馈和兴趣,因为这将有助于提出建议.

有关设计文档中C#7.0解构中包含的内容的更多详细信息.


Pau*_*ado 7

您遇到的问题是编译器无法推断此表达式中的类型:

list.Select(((int x, int y) t) => t.x * 2 + t.y / 2);
Run Code Online (Sandbox Code Playgroud)

但是由于(int, int)(int x, int y)是相同的 CLR 类型 ( System.ValueType<int, int>),如果指定类型参数:

list.Select<(int x, int y), int>(t => t.x * 2 + t.y / 2);
Run Code Online (Sandbox Code Playgroud)

它会起作用。