web-dev-qa-db-fra.com

Tuples et lambdas C # 7

Avec la nouvelle syntaxe c # 7 Tuple, est-il possible de spécifier un lambda avec un tuple en tant que paramètre et d'utiliser des valeurs non compressées dans le lambda?

Exemple:

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

manière normale d'utiliser un Tuple dans Lambda:

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

je m'attendais à du nouveau sucre pour éviter .Item1.Item2, comme:

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

La dernière ligne ne fonctionne pas car elle est traitée comme deux paramètres pour lambda. Je ne suis pas sûr s'il y a un moyen de le faire réellement.

MODIFIER:

J'ai essayé la double parentesis en définition lambda et cela n'a pas fonctionné: ((x,y)) => ..., et c'était peut-être stupide d'essayer, mais la double parenthèse fonctionne vraiment ici:

list.Add((1,2));

De plus, ma question ne concerne pas vraiment les mauvais noms par défaut .Item .Item2 _, il s’agit de décompresser un tuple dans lambda (et peut-être pourquoi il n’est pas implémenté ou impossible). Si vous êtes venu ici pour trouver une solution aux noms par défaut, lisez réponse de Sergey Berezovskiy .

EDIT 2:

Je viens de penser à un cas d'utilisation plus général: est-il possible (ou pourquoi pas) de "déconstruire" le tuple passé à une méthode? Comme ça:

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

Au lieu de cela:

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

Comme vous l'avez observé, pour:

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

On s’attendrait au moins à pouvoir faire ce qui suit:

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

Mais le compilateur C # 7 ne le supporte pas (encore). Il est également raisonnable de vouloir du sucre qui permettrait:

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

Foo(list[0]);

avec le compilateur, convertissant Foo(list[0]); en Foo(list[0].Item1, list[0].Item2); automatiquement.

Aucune de celles-ci n'est actuellement possible. Cependant, le problème Proposition: Déconstruction de tuple dans la liste d'arguments lambda , existe sur le référentiel dotnet/csharplang Sur GitHub, demandant à l'équipe linguistique d'étudier ces fonctionnalités pour une future version de C #. S'il vous plaît, ajoutez vos voix à ce fil de discussion si vous aussi souhaitez bénéficier d'un soutien.

30
David Arno

Vous devez spécifier les noms des propriétés de Tuple (ainsi, les champs de ValueTuple) sinon les noms par défaut seront utilisés, comme vous l'avez vu:

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

Maintenant, Tuple a des champs bien nommés que vous pouvez utiliser

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

N'oubliez pas d'ajouter le paquet System.ValueTuple de NuGet et gardez à l'esprit que ValueTuples sont des structures mutables.


Mise à jour: La déconstruction actuellement représentée uniquement comme une affectation à des variables existantes (deconstructon-assignation) ou à des variables locales nouvellement créées (déclaration de déconstruction). L'algorithme de sélection des membres de la fonction applicable est le même que précédemment:

Chaque argument de la liste d'arguments correspond à un paramètre de la déclaration de membre de la fonction, comme décrit au § 7.5.1.1, et tout paramètre auquel aucun argument ne correspond est un paramètre facultatif.

La variable Tuple est un argument unique. Il ne peut pas correspondre à plusieurs paramètres de la liste des paramètres formels de la méthode.

26
Sergey Berezovskiy

Deconstructions in C # 7.0 prend en charge trois formes:

  • deconstruction-declaration (comme (var x, var y) = e;),
  • déconstruction-assignation (comme (x, y) = e;),
  • et deconstruction-foreach (comme foreach(var(x, y) in e) ...).

D'autres contextes ont été pris en compte, mais leur utilité est probablement décroissante et nous n'avons pas pu les compléter dans le délai C # 7.0. La déconstruction dans une clause let (let (x, y) = e ...) et dans lambdas semble être un bon candidat pour une expansion future.

Ce dernier est en cours de discussion dans https://github.com/dotnet/csharplang/issues/258

Exprimez vos commentaires et votre intérêt là-bas, car cela aidera à défendre les propositions.

Plus de détails sur ce qui était inclus dans la déconstruction C # 7.0 dans le document de conception .

7
Julien Couvreur

Le programme que vous exécutez est l'incapacité du compilateur à déduire le type dans cette expression:

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

Mais depuis (int, int) et (int x, int y) sont le même type de CLR (System.ValueType<int, int>), si vous spécifiez les paramètres de type:

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

Ça va marcher.

3
Paulo Morgado