Renvoyer deux valeurs, Tuple vs ‘out’ vs ‘struct’

Considérons une fonction qui renvoie deux valeurs. Nous pouvons écrire:

// Using out: ssortingng MyFunction(ssortingng input, out int count) // Using Tuple class: Tuple MyFunction(ssortingng input) // Using struct: MyStruct MyFunction(ssortingng input) 

Lequel est la meilleure pratique et pourquoi?

Ils ont chacun leurs avantages et leurs inconvénients.

Les parameters de sortie sont rapides et bon marché, mais exigent que vous passiez dans une variable et que vous vous fiez à la mutation. Il est presque impossible d’utiliser correctement un paramètre out avec LINQ.

Les tuples exercent une pression sur la collecte et ne se documentent pas. “Item1” n’est pas très descriptif.

Les structures personnalisées peuvent être lentes à copier si elles sont volumineuses, mais elles s’auto-documentent et sont efficaces si elles sont petites. Cependant, il est également difficile de définir toute une série de structures personnalisées pour des utilisations sortingviales.

Je serais enclin à la solution de structure personnalisée toutes choses égales par ailleurs. Encore mieux est de faire une fonction qui ne retourne qu’une valeur . Pourquoi renvoyez-vous deux valeurs en premier lieu?

MISE À JOUR: Notez que les tuples en C # 7, livrés six ans après la rédaction de cet article, sont des types de valeur et donc moins susceptibles de créer une pression de collecte.

Je pense que la réponse dépend de la sémantique de ce que fait la fonction et de la relation entre les deux valeurs.

Par exemple, les méthodes TryParse un paramètre out pour accepter la valeur analysée et renvoient une valeur bool pour indiquer si l’parsing a réussi ou non. Les deux valeurs n’appartiennent pas vraiment ensemble, donc, sémantiquement, cela a plus de sens, et l’intention du code est plus facile à lire, pour utiliser le paramètre out .

Si, toutefois, votre fonction retourne des coordonnées X / Y d’un object à l’écran, les deux valeurs appartiennent sémantiquement ensemble et il serait préférable d’utiliser une struct .

Personnellement, j’éviterais d’utiliser un tuple pour tout ce qui serait visible au code externe en raison de la syntaxe maladroite pour récupérer les membres.

Ajoutant aux réponses précédentes, C # 7 apporte des tuples de type valeur, contrairement à System.Tuple qui est un type de référence et offre également une sémantique améliorée.

Vous pouvez toujours les laisser sans nom et utiliser la syntaxe .Item* :

 (ssortingng, ssortingng, int) getPerson() { return ("John", "Doe", 42); } var person = getPerson(); person.Item1; //John person.Item2; //Doe person.Item3; //42 

Mais ce qui est vraiment puissant avec cette nouvelle fonctionnalité, c’est la possibilité d’avoir des tuples nommés. Nous pourrions donc réécrire ce qui précède comme ceci:

 (ssortingng FirstName, ssortingng LastName, int Age) getPerson() { return ("John", "Doe", 42); } var person = getPerson(); person.FirstName; //John person.LastName; //Doe person.Age; //42 

La destruction est également supscope:

(ssortingng firstName, ssortingng lastName, int age) = getPerson()

J’utiliserai l’approche de l’utilisation du paramètre Out car dans la seconde approche, vous devez créer et object de la classe Tuple, puis y append de la valeur, ce qui est une opération coûteuse comparée au retour du paramètre value in out. Bien que si vous voulez renvoyer plusieurs valeurs dans la classe Tuple (ce qui est impossible en retournant simplement un paramètre), j’irai pour la deuxième approche.

Vous n’avez pas mentionné une option supplémentaire, à savoir avoir une classe personnalisée au lieu de struct. Si les données ont une sémantique associée à des fonctions, ou si la taille de l’instance est suffisamment grande (> 16 octets en règle générale), une classe personnalisée peut être préférée. L’utilisation de “out” n’est pas recommandée dans les API publiques en raison de son association aux pointeurs et de la nécessité de comprendre le fonctionnement des types de référence.

https://msdn.microsoft.com/en-us/library/ms182131.aspx

Tuple est bon pour un usage interne, mais son utilisation est difficile dans les API publiques. Donc, mon vote est entre struct et class pour API publique.

Il n’y a pas de “meilleure pratique”. C’est ce que vous êtes à l’aise et ce qui fonctionne le mieux dans votre situation. Tant que vous êtes cohérent avec cela, aucune des solutions que vous avez publiées ne pose de problème.