简体   繁体   English

C# 7 元组和 lambdas

[英]C# 7 tuples and lambdas

With new c# 7 tuple syntax, is it possible to specify a lambda with a tuple as parameter and use unpacked values inside the lambda?使用新的 c# 7 元组语法,是否可以指定一个带有元组作为参数的 lambda 并在 lambda 中使用解压值?

Example:例子:

var list = new List<(int,int)>();

normal way to use a tuple in lambda:在 lambda 中使用元组的正常方法:

list.Select(value => value.Item1*2 + value.Item2/2);

i expected some new sugar to avoid .Item1 .Item2 , like:我希望一些新的糖可以避免.Item1 .Item2 ,例如:

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

The last line does not work because it is treated as two parameters for lambda.最后一行不起作用,因为它被视为 lambda 的两个参数。 I am not sure if there is a way to do it actually.我不确定是否有办法真正做到这一点。

EDIT:编辑:

I tried double parentesis in lambda definition and it didn't work: ((x,y)) => ... , and maybe it was stupid to try, but double parenthesis actually work here:我在 lambda 定义中尝试了双括号,但没有奏效: ((x,y)) => ... ,也许尝试起来很愚蠢,但双括号实际上在这里起作用:

list.Add((1,2));

Also, my question is not quite about avoiding ugly default names .Item .Item2 , it is about actual unpacking a tuple in lambda (and maybe why it's not implemented or not possible).另外,我的问题并不是关于避免丑陋的默认名称.Item .Item2 ,而是关于在 lambda 中实际解包一个元组(也许为什么它没有实现或不可能实现)。 If you came here for a solution to default names, read Sergey Berezovskiy's answer .如果您来这里是为了解决默认名称,请阅读Sergey Berezovskiy 的回答

EDIT 2:编辑2:

Just thought of a more general use case: is it possible (or why not) to "deconstruct" tuple passed to a method?只是想到了一个更一般的用例:是否有可能(或为什么不)“解构”传递给方法的元组? Like this:像这样:

void Foo((int,int)(x,y)) { x+y; }

Instead of this:取而代之的是:

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

As you have observed, for:正如您所观察到的,对于:

var list = new List<(int,int)>();

One would at least expect to be able to do the following:人们至少希望能够做到以下几点:

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

But the C# 7 compiler doesn't (yet) support this.但是 C# 7 编译器(还)不支持这一点。 It is also reasonable to desire sugar that would allow the following:需要糖以允许以下内容也是合理的:

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

Foo(list[0]);

with the compiler converting Foo(list[0]);与编译器转换Foo(list[0]); to Foo(list[0].Item1, list[0].Item2);Foo(list[0].Item1, list[0].Item2); automatically.自动地。

Neither of these is currently possible.目前这两种方法都不可能。 However, the issue, Proposal: Tuple deconstruction in lambda argument list , exists on the dotnet/csharplang repo on GitHub, requesting that the language team consider these features for a future version of C#.但是,GitHub 上的dotnet/csharplang库中存在问题Proposal: Tuple deconstruction in lambda argument list ,要求语言团队在 C# 的未来版本中考虑这些功能。 Please do add your voices to that thread if you too would like to see support for this.如果您也希望看到对此的支持,请务必将您的声音添加到该线程中。

You should specify names of tuple properties (well, ValueTuple have fields) otherwise default names will be used, as you have seen:您应该指定元组属性的名称(好吧,ValueTuple 有字段),否则将使用默认名称,如您所见:

var list = new List<(int x, int y)>();

Now tuple have nicely named fields which you can use现在元组有很好命名的字段,您可以使用

list.Select(t => t.x * 2 + t.y / 2)

Don't forget to add System.ValueTuple package from NuGet and keep in mind that ValueTuples are mutable structs.不要忘记从 NuGet 添加System.ValueTuple包,并记住 ValueTuples 是可变结构。


Update: Deconstruction currently represented only as an assignment to existing variables (deconstructon-assignment) or to newly created local variables (deconstruction-declaration).更新:解构当前仅表示为对现有变量(解构赋值)或新创建的局部变量(解构声明)的赋值。 Applicable function member selection algorithm is the same as before:适用的函数成员选择算法与之前相同:

Each argument in argument list corresponds to a parameter in the function member declaration as described in §7.5.1.1, and any parameter to which no argument corresponds is an optional parameter.参数列表中的每个参数对应于第 7.5.1.1 节中描述的函数成员声明中的一个参数,任何没有参数对应的参数都是可选参数。

Tuple variable is a single argument.元组变量是单个参数。 It cannot correspond to several parameters in the formal parameters list of the method.它不能对应方法的形参列表中的几个参数。

Deconstructions in C# 7.0 support three forms: C# 7.0 中的解构支持三种形式:

  • deconstruction-declaration (like (var x, var y) = e; ),解构声明(如(var x, var y) = e; ),
  • deconstruction-assignment (like (x, y) = e; ),解构赋值(如(x, y) = e; ),
  • and deconstruction-foreach (like foreach(var(x, y) in e) ... ).和 deconstruction-foreach (如foreach(var(x, y) in e) ... )。

Other contexts were considered, but likely have decreasing utility and we couldn't complete them in the C# 7.0 timeframe.考虑了其他上下文,但实用性可能会下降,我们无法在 C# 7.0 时间范围内完成它们。 Deconstruction in a let clause ( let (x, y) = e ... ) and in lambdas seem good candidates for future expansion. let 子句( let (x, y) = e ... )和 lambdas 中的解构似乎是未来扩展的好候选者。

The latter is being discussed in https://github.com/dotnet/csharplang/issues/258后者正在https://github.com/dotnet/csharplang/issues/258中讨论

Do voice your feedback and interest there, as it will help champion proposals.请在那里表达您的反馈和兴趣,因为这将有助于支持提案。

More details on what was included in C# 7.0 deconstruction in the design doc .有关设计文档中 C# 7.0 解构中包含的内容的更多详细信息。

The problem you're running into is the inability of the compiler to infer the type in this expression:您遇到的问题是编译器无法推断此表达式中的类型:

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

But since (int, int) and (int x, int y) are the same CLR type ( System.ValueType<int, int> ), if you specify the type parameters:但由于(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);

It will work.它会起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM