C # 7 tuplas y lambdas


Con la nueva sintaxis de la tupla de c# 7, ¿es posible especificar una lambda con una tupla como parámetro y usar valores descomprimidos 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 un poco de azúcar nuevo para evitar .Item1 .Item2, me gusta:

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 realidad.

EDITAR:

Probé el doble la parentesis en la definición lambda y no funcionó: ((x,y)) => ..., y tal vez fue estúpido intentarlo, pero el doble paréntesis realmente funciona aquí:

list.Add((1,2));

Además, mi pregunta no es acerca de evitar nombres por defecto feos .Item .Item2, se trata de desempaquetar una tupla en lambda (y tal vez por qué no se implementa o no es posible). Si ha venido aquí para encontrar una solución a los nombres predeterminados, lea La respuesta de Sergey Berezovskiy.

EDITAR 2:

Acabo de pensar en un caso de uso más general: ¿es posible (o por qué no) "deconstruir" la tupla pasada a un método? Así:

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

En lugar de esto:

void Foo((int x,int y) value) { value.x+value.y }
Author: Community, 2017-03-29

4 answers

Como usted ha 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 soporta 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.

Ninguna de ellas es posible actualmente. Sin embargo, el problema, Propuesta: Deconstrucción de tuplas en la lista de argumentos lambda , existe en el repositorio dotnet/csharplang en GitHub, solicitando que el equipo de lenguaje considere estas características para una versión futura de C#. Por favor, agregue sus voces a ese hilo si también desea ver soporte para esto.

 19
Author: David Arno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-29 09:31:29

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

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

Ahora la tupla tiene campos bien nombrados que puede usar

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

No olvides agregar Sistema.ValueTuple paquete de NuGet y tenga en cuenta que los ValueTuples son estructuras mutables.


Actualización: La deconstrucción se representa actualmente solo como una asignación a variables existentes (deconstructon-assignment) o a variables locales 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.

La variable Tupla es un único argumento. No puede corresponder a varios parámetros en la lista formal de parámetros del método.

 25
Author: Sergey Berezovskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-29 03:35:04

Las deconstrucciones en C# 7.0 admiten tres formas:

  • deconstrucción-declaración (como (var x, var y) = e;),
  • deconstrucción-asignación (como (x, y) = e;),
  • y deconstrucción-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 temporal 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 intereses allí, ya que ayudará a defender las propuestas.

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

 6
Author: Julien Couvreur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-08 21:24:22

El programa en el que se encuentra es la incapacidad del compilador para inferir el tipo en esta expresión:

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

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

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

Funcionará.

 2
Author: Paulo Morgado,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-29 06:54:15