T # 7 tuplas y lambdas

Con la nueva syntax de la tupla c # 7, ¿es posible especificar una lambda con una tupla como parámetro y usar valores desempaquetados dentro de la lambda?

Ejemplo:

var list = new List(); 

Forma normal de usar una tupla en lambda:

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

Esperaba algo de azúcar nuevo para evitar .Item1 .Item2 , como:

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

La última línea no funciona porque se trata como dos parámetros para lambda. No estoy seguro de si hay una manera de hacerlo en realidad.

EDITAR:

Intenté doble parentesis en la definición de lambda y no funcionó: ((x,y)) => ... , y tal vez fue una estupidez intentarlo, pero el paréntesis doble en realidad funciona aquí:

 list.Add((1,2)); 

Además, mi pregunta no se trata en absoluto de evitar los nombres por defecto feos. .Item .Item2 . .Item .Item2 , se trata de desempaquetar una tupla en Lambda (y tal vez por qué no está implementado o no es posible). Si vino aquí para encontrar una solución a los nombres predeterminados, lea la respuesta de Sergey Berezovskiy .

EDIT 2:

Pensé en un caso de uso más general: ¿es posible (o por qué no) el “deconstruir” tuple pasado a un método? Me gusta esto:

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

En lugar de esto:

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

Como has observado, para:

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

Al menos uno esperaría poder hacer lo siguiente:

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

Pero el comstackdor C # 7 no (todavía) soporta esto. También es razonable desear azúcar que permita lo siguiente:

 void Foo(int x, int y) => ... Foo(list[0]); 

con el comstackdor que convierte Foo(list[0]); a Foo(list[0].Item1, list[0].Item2); automáticamente.

Ninguno de estos es actualmente posible. Sin embargo, el problema, Propuesta: Deconstrucción de tupla en la lista de argumentos lambda , existe en el repository dotnet/csharplang en GitHub, solicitando que el equipo de idiomas considere estas características para una versión futura de C #. Por favor, agregue sus voces a ese hilo si a usted también le gustaría ver soporte para esto.

Debe especificar los nombres de las propiedades de la tupla (bueno, ValueTuple tiene campos) de lo contrario, se utilizarán los nombres predeterminados, como ha visto:

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

Ahora la tupla tiene campos bien nombrados que puedes usar

 list.Select(t => tx * 2 + ty / 2) 

No olvide agregar el paquete System.ValueTuple de NuGet y tenga en cuenta que ValueTuples son estructuras mutables.


Actualización: la deconstrucción se representa actualmente solo como una asignación a las variables existentes (asignación a la deconstrucción) o a las variables locales recién creadas (statement a la deconstrucción). El algoritmo de selección de miembro de función aplicable es el mismo que antes:

Cada argumento en la lista de argumentos corresponde a un parámetro en la statement de miembro de función como se describe en §7.5.1.1, y cualquier parámetro al que no corresponda ningún argumento es un parámetro opcional.

La variable tupla es un solo argumento. No puede corresponder a varios parámetros en la lista de parámetros formales del método.

Las deconstrucciones en C # 7.0 admiten tres formas:

  • deconstrucción-statement (como (var x, var y) = e; ),
  • deconstrucción-asignación (como (x, y) = e; ),
  • y deconstruction-foreach (como foreach(var(x, y) in e) ... ).

Se consideraron otros contextos, pero probablemente tienen una utilidad decreciente y no pudimos completarlos en el marco de tiempo de C # 7.0. La deconstrucción en una cláusula let ( let (x, y) = e ... ) y en lambdas parecen ser buenos candidatos para una futura expansión.

Este último se está discutiendo en https://github.com/dotnet/csharplang/issues/258

Exprese sus comentarios e interés allí, ya que ayudará a defender las propuestas.

Más detalles sobre lo que se incluyó en la deconstrucción C # 7.0 en el documento de diseño .

El progtwig que está ejecutando es la incapacidad del comstackdor para inferir el tipo en esta expresión:

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

Pero dado que (int, int) y (int x, int y) son del mismo tipo CLR ( System.ValueType ), si especifica los parámetros de tipo:

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

Funcionará.