2017-06-30 6 views
11

Puisque le C# 7 introduit des tuples de valeur, y a-t-il un scénario significatif où ils conviennent mieux que les tuples?Les types anonymes C# sont-ils redondants dans C# 7

Par exemple, la ligne suivante

collection.Select((x, i) => (x, i)).Where(y => arr[y.i].f(y.x)).ToArray(); 

fait la ligne suivante

collection.Select((x, i) => new {x, i}).Where(y => arr[y.i].f(y.x)).ToArray(); 

redondant.

Quel serait le cas d'utilisation où l'un est mieux utilisé que l'autre (pour des raisons de performance ou d'optimisation)?

Évidemment, s'il y a besoin de plus de six champs, les tuples ne peuvent pas être utilisés, mais y a-t-il quelque chose de plus nuancé?

+3

Peut-être la lisibilité? 'new {x, i}' rend tout à fait clair que c'est un nouvel objet qui est retourné, alors que j'ai dû comparer les deux exemples pour comprendre ce que fait le premier. Mais alors ça pourrait être moi. – stybl

+13

D'une part, ils sont pris en charge dans les arbres d'expressions et les littéraux de tuple ne sont pas ... –

+7

Notez que votre exemple ne compilerait pas dans C# 7.0 car '(x, i)' a des éléments de tuple sans nom, mais ils sont implicitement nommé dans C# 7.1. –

Répondre

12

Il existe plusieurs différences entre les types anonymes et C# 7 tuples, qui peut ou ne peut pas faire un plus approprié que l'autre dans certaines situations:

  • C# 7 sont tuples ValueTuple<> s. Cela signifie qu'ils sont les types de valeur alors que les types anonymes sont des types de référence.
  • Les tuples permettent le typage statique au moment de la compilation car ils sont un type qui peut être exprimé explicitement. En tant que tels, vous pouvez les utiliser comme arguments de méthode, types de retour, etc.
  • Les membres d'un type anonyme sont des propriétés réelles qui existent sur le type. Les articles de Tuple sont champs.
  • Les propriétés d'un type anonyme ont un nom réel, tandis que les champs d'un tuple sont simplement nommés ItemN (pour les nombres N). Les étiquettes sont juste des informations de métadonnées qui sont principalement utilisées par le compilateur et ne sont pas conservées avec l'objet tuple réel.
  • Parce que la création d'un type anonyme crée réellement un type sous le capot, vous avez un niveau de sécurité de type avec eux. Puisque les tuples ne sont que des conteneurs génériques avec des arguments de type appliqué, vous n'avez pas de sécurité de type complète avec eux. Par exemple un (int, int) tuple pour une taille serait entièrement compatible avec un (int, int) tuple pour une position , alors que les types anonymes sont complètement fermés.
  • Comme Jon Skeet l'a mentionné, la syntaxe du tuple C# 7 est currently not supported dans les arbres d'expression.
+0

Belle réponse. Incluez-vous l'argument de Jon Skeet sur les littéraux en tuple qui ne fonctionnent pas dans les arbres d'expression? –

+0

J'aime la réponse car elle fournit des détails d'implémentation sur 'ValueTuple's. Mais il ne répond toujours pas à la question OP: existe-t-il des scénarios où le type anonyme est meilleur que ValueTuple? Le point 5 (pour autant que je comprenne) est plus à propos de l'utilisation de types ordinaires au lieu de ValueTuple. –

+0

@VadimOvchinnikov Oui, bien sûr, il existe des scénarios. Ces scénarios où la différence entre ces deux caractéristiques sont pertinentes. - Si vous avez besoin d'un exemple, prenez [Dapper] (https://github.com/StackExchange/Dapper) où vous pouvez passer un type anonyme avec des arguments de requête * named *. Puisque les objets tuple n'ont aucun nom associé, vous ne pouvez pas faire cela avec eux. – poke

1

réponse actuelle par @poke est correcte et constate des différences entre tuple et types anonymes. Je vais discuter de la raison pour laquelle vous les utiliseriez ou préféreriez les utiliser plutôt que les autres.

Deux nouvelles fonctions C# 7 suppriment les types anonymes. ValueTuples et Records.

La principale raison pour laquelle vous n'utiliser des types anonymes est

  • vous ne pouvez pas utiliser des types anonymes dans le monde et ils sont uniquement type sûrs lorsqu'ils sont utilisés localement.ne pas être local, vous devez le traiter comme objet dynamic qui a des performances importantes en tête

Les raisons que vous préférez tuple sur les types anonymes.

  • ils sont de type sécurité dans tous les sens. (Indépendamment de nommer)

  • ils peuvent être utilisés comme arguments de la méthode, des arguments de type, champ et à peu près partout. (oui je l'ai dit à peu près, il ya des endroits qui doivent adopter avec des tuples, sa question de temps.)

  • puisqu'ils peuvent être utilisés comme argument de type, vous préférez probablement envelopper un ensemble léger de paramètres en un seul paramètre. comme Stack<(min, mid, max)>

  • vous pouvez changer les options de nommage à chaque fois que vous vous sentez le besoin, dans le nom de contexte générique item peut satisfaire et dans un contexte plus spécifique dont vous avez besoin nom plus spécifique aussi, comme car

  • ils sont implicitement convertibles, int, int peut être affecté à (int, long) sans conversion explicite.

  • ils sont utilisés dans Deconstruct s. ce qui apporte beaucoup de sucre syntaxique à la langue.

  • vous pouvez avoir plusieurs missions et déclarations comme (int x, int y) = (0, 1)

Ayant toutes ces fonctionnalités, il y a encore une raison pour laquelle vous pouvez préférer type anonyme sur tuple.

  • types anonymes sont le type de référence, mais sont tuples type de valeur.

mais que faire si vous souhaitez utiliser globalement le type anonyme? préférez-vous avoir des objets dynamiques ou des objets typés statiquement?

La fonction Enregistrements entrants à nouveau détruit les types anonymes. Avec les enregistrements, vous définissez votre classe de manière courte, concise et pratique. pas un gros problème. juste une seule ligne

public class Point(X, Y); 

Tapez la sécurité partout, et vous avez également le type de référence à la main. ces deux nouvelles fonctionnalités apportent tout pour vaincre les types anonymes.

Notez que les enregistrements ne sont pas encore ajouté, nous avons juste à attendre.

ne reste l'utilisation réelle des types anonymes seront

  • ils servent toujours aussi fonction rétrocompatible

  • ils peuvent être utilisés dans requêtes LINQ lorsque vous utilisez type anonyme localement. par conséquent, je ne dis pas que les types anonymes sont redondants.

Comme je l'ai dit, ValueTuples n'est pas encore compatible avec tous les composants. C'est juste une question de temps, mais c'est comme ça que ça va être à l'avenir.

assez d'arguments. à mon humble avis, l'utilisation de types anonymes devient rare, les anciens programmeurs peuvent toujours utiliser le type anonyme dans Linq par habitude.