C#7元组和lambda

C#7元组和lambda,c#,lambda,tuples,c#-7.0,C#,Lambda,Tuples,C# 7.0,使用新的c#7元组语法,是否可以使用元组作为参数指定lambda,并在lambda中使用未打包的值 例如: var list = new List<(int,int)>(); 我希望一些新糖可以避免.Item1.Item2,比如: list.Select((x,y) => x*2 + y/2); 最后一行不起作用,因为它被视为lambda的两个参数。我不确定是否有办法做到这一点 编辑: 我在lambda定义中尝试了双亲,但没有成功:((x,y))=>…,也许尝试起来很愚蠢,

使用新的c#7元组语法,是否可以使用元组作为参数指定lambda,并在lambda中使用未打包的值

例如:

var list = new List<(int,int)>();
我希望一些新糖可以避免
.Item1
.Item2
,比如:

list.Select((x,y) => x*2 + y/2);
最后一行不起作用,因为它被视为lambda的两个参数。我不确定是否有办法做到这一点

编辑:

我在lambda定义中尝试了双亲,但没有成功:
((x,y))=>…
,也许尝试起来很愚蠢,但双括号实际上在这里起作用:

list.Add((1,2));
另外,我的问题并不是要避免难看的默认名称
.Item.Item2
,而是要在lambda中实际解包一个元组(以及为什么它没有实现或不可能实现)。如果您是来这里寻求默认名称的解决方案,请阅读

编辑2:

考虑一个更一般的用例:是否可以(或者为什么不可以)“解构”传递给方法的元组?像这样:

void Foo((int,int)(x,y)) { x+y; }
与此相反:

void Foo((int x,int y) value) { value.x+value.y }

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

var list = new List<(int x, int y)>();
不要忘记从NuGet添加System.ValueTuple包,并记住ValueTuple是可变结构


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

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


元组变量是单个参数。它不能对应于方法的形式参数列表中的多个参数。

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

list.Select(((int x, int y) t) => t.x * 2 + t.y / 2);
但是由于
(int,int)
(int x,int y)
是相同的CLR类型(
System.ValueType
),如果指定类型参数:

list.Select<(int x, int y), int>(t => t.x * 2 + t.y / 2);
list.Select(t=>t.x*2+t.y/2);

它将起作用。

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

var list = new List<(int,int)>();
但是C#7编译器(还)不支持这一点。同样合理的做法是,需要糖来满足以下条件:

list.Select((x,y) => x*2 + y/2);
void Foo(int x, int y) => ...

Foo(list[0]);
使用编译器转换
Foo(列表[0])
Foo(列表[0].Item1,列表[0].Item2)自动

这两项目前都不可能。然而,这个问题存在于 dotNET/cSalpLang< RePo上,在GITHUB上,请求语言团队考虑这些特性以供将来的C版本使用。如果您也希望看到对这一点的支持,请将您的声音添加到该线程中。

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

  • 解构声明(如
    (varx,vary)=e;
  • 解构赋值(如
    (x,y)=e;
  • 以及对foreach的解构(比如
    foreach(e中的var(x,y)…
考虑了其他上下文,但可能会降低效用,我们无法在C#7.0时间框架内完成它们。let子句(
let(x,y)=e…
)和lambdas中的解构似乎是未来扩展的良好候选

后者正在讨论中

一定要在那里表达你的反馈和兴趣,因为这将有助于支持提案


关于C#7.0解构中所包含内容的更多详细信息。

很好,但只是重命名,值仍然是传递给lambda的单个对象的字段。我很好奇是否有办法将其解构为多个变量。@拉斯特:据我所知,元组解构仅在变量声明可以包含元组赋值的上下文中有效。这将排除参数列表。谢尔盖的例子似乎很清楚;有什么不适合你的需要?@Peter Duniho这只是我的好奇心。我认为解构或类似的东西在这种情况下可能有用。@Rast
Enumerable.Select
有一个
Func
委托作为参数。它接受TSource类型的单个参数,您不能更改that@Rast:可能,但不在参数列表中,其中不允许指定非默认值。您可以改为执行类似于
list.Select(t=>{(intx,inty)=t;返回x*2+y/2}),但在这一点上,我认为您正在失去元组语法的简洁性。
list.Select((x,y) => x*2 + y/2);
void Foo(int x, int y) => ...

Foo(list[0]);