Con la nueva sintaxis de tupla de 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<(int,int)>();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:
Probé el paréntesis doble en la definición lambda y no funcionó: ((x,y)) => ... , y tal vez fue estúpido intentarlo, pero el paréntesis doble realmente funciona aquí:
list.Add((1,2)); Además, mi pregunta no se trata de evitar nombres predeterminados feos .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í en busca de una solución para los nombres predeterminados, lea la respuesta de Sergey Berezovskiy .
EDITAR 2:
Solo pensé en un caso de uso más general: ¿es posible (o por qué no) "deconstruir" la tupla pasada a un método? Como 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 compilador de C# 7 (todavía) no es compatible con esto. También es razonable desear azúcar que permita lo siguiente:
void Foo(int x, int y) => ... Foo(list[0]); con el compilador convirtiendo Foo(list[0]); a Foo(list[0].Item1, list[0].Item2); automáticamente.
Ninguno de estos es posible actualmente. Sin embargo, el problema, Proposal: Tuple deconstruction in lambda argument list , existe en el repositorio dotnet/csharplang en GitHub y solicita que el equipo de lenguaje considere estas características para una versión futura de C#. Agregue sus voces a ese hilo si a usted también le gustaría ver apoyo 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 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 actualmente se representa solo como una asignación a variables existentes (deconstrucción-asignación) o a variables locales recién creadas (deconstrucción-declaración). El algoritmo de selección de miembros de la función aplicable es el mismo que antes:
Cada argumento en la lista de argumentos corresponde a un parámetro en la declaración del miembro de la 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.
Tupla variable 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:
(var x, var y) = e; ),(x, y) = e; ),foreach(var(x, y) in e) ... ). Se consideraron otros contextos, pero es probable que tengan 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 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 impulsar las propuestas.
Más detalles sobre lo que se incluyó en la deconstrucción de C# 7.0 en el documento de diseño .