L'utilisation de tuples .NET 4.0 dans mon code C # est-elle une mauvaise décision de conception?

166

Avec l'ajout de la classe Tuple dans .net 4, j'ai essayé de décider si les utiliser dans ma conception est un mauvais choix ou non. À mon avis, un Tuple peut être un raccourci pour écrire une classe de résultat (je suis sûr qu'il existe également d'autres utilisations).

Donc ça:

public class ResultType
{
    public string StringValue { get; set; }
    public int IntValue { get; set; }
}

public ResultType GetAClassedValue()
{
    //..Do Some Stuff
    ResultType result = new ResultType { StringValue = "A String", IntValue = 2 };
    return result;
}

Est équivalent à ceci:

public Tuple<string, int> GetATupledValue()
{
    //...Do Some stuff
    Tuple<string, int> result = new Tuple<string, int>("A String", 2);
    return result;
}

Donc , mettre de côté la possibilité que je manque le point de tuples, est l'exemple avec un Tuple un mauvais choix de conception? Pour moi, cela semble moins encombrant, mais pas aussi auto-documenté et propre. Cela signifie qu'avec le type ResultType, il est très clair plus tard ce que chaque partie de la classe signifie mais vous avez du code supplémentaire à maintenir. Avec le, Tuple<string, int>vous devrez rechercher et comprendre ce que chacun Itemreprésente, mais vous écrivez et maintenez moins de code.

Toute expérience que vous auriez eue avec ce choix serait grandement appréciée.

Jason Webb
la source
16
@Boltbait: parce que le tuple est de la théorie des ensembles en.wikipedia.org/wiki/Tuple
Matthew Whited
16
@BoltBait: Un "tuple" est un ensemble ordonné de valeurs, et n'a pas nécessairement quoi que ce soit à voir avec les lignes d'une base de données.
FrustratedWithFormsDesigner
19
Les tuples en c # seraient encore plus agréables s'il y avait une bonne action de déballage de tuple :)
Justin
4
@John Saunders Ma question porte spécifiquement sur les décisions de conception en c #. Je n'utilise aucun autre langage .net, donc je ne suis pas sûr de l'impact des tuples. Alors je l'ai marqué c #. Cela m'a semblé raisonnable mais le changement vers .net est bien aussi je suppose.
Jason Webb
13
@John Saunders: Je suis presque sûr qu'il pose des questions sur les décisions de conception relatives à l'utilisation ou non de Tuples dans une application qui est écrite uniquement en C #. Je ne pense pas qu'il pose des questions sur les décisions de conception qui ont conduit à la création du langage C #.
Brett Widmeier

Réponses:

163

Les tuples sont parfaits si vous contrôlez à la fois leur création et leur utilisation - vous pouvez maintenir le contexte, ce qui est essentiel pour les comprendre.

Sur une API publique, cependant, ils sont moins efficaces. Le consommateur (pas vous) doit deviner ou consulter la documentation, en particulier pour des choses comme Tuple<int, int>.

Je les utiliserais pour les membres privés / internes, mais utiliserais les classes de résultats pour les membres publics / protégés.

Cette réponse contient également quelques informations.

Bryan Watts
la source
19
La différence entre public / privé est vraiment importante, merci de l'avoir soulevée. Renvoyer des tuples dans votre API publique est une très mauvaise idée, mais en interne, là où les choses peuvent être étroitement couplées (mais ce n'est pas grave ), c'est bien.
Clinton Pierce
36
Étroitement couplé ou étroitement multiplié? ;)
contactmatt
Une documentation appropriée ne pourrait-elle pas être utile ici? Par exemple, Scala StringOps(essentiellement une classe de «méthodes d'extension» pour Java String) a une méthode parition(Char => Boolean): (String, String)(prend un prédicat, retourne un tuple de 2 chaînes). La sortie est évidente (évidemment, l'un va être les caractères pour lesquels le prédicat était vrai et l'autre pour lequel il était faux, mais on ne sait pas qui est lequel). C'est la documentation qui clarifie cela (et la correspondance de modèle peut être utilisée pour clarifier l'utilisation qui est laquelle).
Kat
@Mike: Cela rend difficile de se tromper et il est facile de se tromper, la marque d'une API qui causera de la douleur à quelqu'un quelque part :-)
Bryan Watts
79

À mon avis, un Tuple est un raccourci pour écrire une classe de résultat (je suis sûr qu'il existe également d'autres utilisations).

Il existe en effet d'autres utilisations intéressantesTuple<> - la plupart d'entre elles impliquent d'abstraire la sémantique d'un groupe particulier de types partageant une structure similaire et de les traiter simplement comme un ensemble ordonné de valeurs. Dans tous les cas, l'un des avantages des tuples est qu'ils évitent d'encombrer votre espace de noms avec des classes de données uniquement qui exposent des propriétés mais pas des méthodes.

Voici un exemple d'utilisation raisonnable pour Tuple<>:

var opponents = new Tuple<Player,Player>( playerBob, playerSam );

Dans l'exemple ci-dessus, nous voulons représenter une paire d'adversaires, un tuple est un moyen pratique de coupler ces instances sans avoir à créer une nouvelle classe. Voici un autre exemple:

var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );

Une main de poker peut être considérée comme un simple jeu de cartes - et le tuple (peut être) une manière raisonnable d'exprimer ce concept.

en mettant de côté la possibilité que je manque le point des tuples, est-ce que l'exemple avec un Tuple est un mauvais choix de conception?

Le renvoi d' Tuple<>instances fortement typées dans le cadre d'une API publique pour un type public est rarement une bonne idée. Comme vous le reconnaissez vous-même, les tuples exigent que les parties impliquées (auteur de la bibliothèque, utilisateur de la bibliothèque) se mettent d'accord à l'avance sur le but et l'interprétation des types de tuple utilisés. Il est déjà assez difficile de créer des API intuitives et claires, l'utilisation Tuple<>publique obscurcit uniquement l'intention et le comportement de l'API.

Les types anonymes sont également une sorte de tuple - cependant, ils sont fortement typés et vous permettent de spécifier des noms clairs et informatifs pour les propriétés appartenant au type. Mais les types anonymes sont difficiles à utiliser dans différentes méthodes - ils ont été principalement ajoutés pour prendre en charge des technologies telles que LINQ où les projections produiraient des types auxquels nous ne voudrions normalement pas attribuer des noms. (Oui, je sais que les types anonymes avec les mêmes types et propriétés nommées sont consolidés par le compilateur).

Ma règle de base est la suivante: si vous le renvoyez depuis votre interface publique, faites-en un type nommé .

Mon autre règle de base pour l'utilisation des tuples est la suivante: nommez les arguments de méthode et les variables localc de type Tuple<>aussi clairement que possible - faites en sorte que le nom représente la signification des relations entre les éléments du tuple. Pensez à mon var opponents = ...exemple.

Voici un exemple de cas réel où j'ai utilisé Tuple<>pour éviter de déclarer un type de données uniquement à utiliser uniquement dans mon propre assembly . La situation implique le fait que lors de l'utilisation de dictionnaires génériques contenant des types anonymes, il devient difficile d'utiliser la TryGetValue()méthode pour trouver des éléments dans le dictionnaire car la méthode nécessite un outparamètre qui ne peut pas être nommé:

public static class DictionaryExt 
{
    // helper method that allows compiler to provide type inference
    // when attempting to locate optionally existent items in a dictionary
    public static Tuple<TValue,bool> Find<TKey,TValue>( 
        this IDictionary<TKey,TValue> dict, TKey keyToFind ) 
    {
        TValue foundValue = default(TValue);
        bool wasFound = dict.TryGetValue( keyToFind, out foundValue );
        return Tuple.Create( foundValue, wasFound );
    }
}

public class Program
{
    public static void Main()
    {
        var people = new[] { new { LastName = "Smith", FirstName = "Joe" },
                             new { LastName = "Sanders", FirstName = "Bob" } };

        var peopleDict = people.ToDictionary( d => d.LastName );

        // ??? foundItem <= what type would you put here?
        // peopleDict.TryGetValue( "Smith", out ??? );

        // so instead, we use our Find() extension:
        var result = peopleDict.Find( "Smith" );
        if( result.First )
        {
            Console.WriteLine( result.Second );
        }
    }
}

PS Il existe un autre moyen (plus simple) de contourner les problèmes liés aux types anonymes dans les dictionnaires, et c'est d'utiliser le varmot - clé pour laisser le compilateur «déduire» le type pour vous. Voici cette version:

var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
   // use foundItem...
}
LBushkin
la source
5
@stakx: Oui, je suis d'accord. Mais gardez à l'esprit - l'exemple est en grande partie destiné à illustrer des cas où l'utilisation d'un Tuple<> pourrait avoir un sens. Il y a toujours des alternatives ...
LBushkin
1
Je pense que le remplacement des paramètres par un Tuple, comme dans TryGetValue ou TryParse, est l'un des rares cas où il peut être judicieux qu'une API publique renvoie un Tuple. En fait, au moins un langage .NET modifie automatiquement cette API pour vous.
Joel Mueller
1
@stakx: Les tuples sont également immuables, alors que les tableaux ne le sont pas.
Robert Paulson
2
J'ai compris que les tuples ne sont utiles qu'en tant qu'objets de joueur de poker immuables.
Gennady Vanin Геннадий Ванин
2
+1 Excellente réponse - J'adore vos deux premiers exemples qui ont en fait légèrement changé d'avis. Je n'ai jamais vu d'exemples auparavant où un tuple était au moins aussi approprié qu'une structure ou un type personnalisé. Cependant, votre dernier "exemple réel" ne me semble plus apporter beaucoup de valeur. Les deux premiers exemples sont parfaits et simples. Le dernier est un peu difficile à comprendre et votre type "PS" le rend inutile puisque votre approche alternative est beaucoup plus simple et ne nécessite pas de tuples.
chiccodoro
18

Les tuples peuvent être utiles ... mais ils peuvent aussi être pénibles plus tard. Si vous avez une méthode qui renvoie, Tuple<int,string,string,int>comment savez-vous quelles sont ces valeurs plus tard. Étaient-ils ID, FirstName, LastName, Ageou étaient-ils UnitNumber, Street, City, ZipCode.

Matthew Whited
la source
9

Les tuples sont un ajout assez décevant au CLR du point de vue d'un programmeur C #. Si vous avez une collection d'éléments dont la longueur varie, vous n'avez pas besoin qu'ils aient des noms statiques uniques au moment de la compilation.

Mais si vous avez une collection de longueur constante, cela implique que les emplacements fixes de la collection ont chacun une signification prédéfinie spécifique. Et il est toujours préférable de leur donner des noms de statiques appropriés dans ce cas, plutôt que d' avoir à se rappeler l'importance de Item1, Item2etc.

Les classes anonymes en C # fournissent déjà une excellente solution à l'utilisation privée la plus courante des tuples, et elles donnent des noms significatifs aux éléments, donc ils sont en fait supérieurs dans ce sens. Le seul problème est qu'ils ne peuvent pas s'échapper des méthodes nommées. Je préférerais voir cette restriction levée (peut-être uniquement pour les méthodes privées) plutôt que d'avoir un support spécifique pour les tuples en C #:

private var GetDesserts()
{
    return _icecreams.Select(
        i => new { icecream = i, topping = new Topping(i) }
    );
}

public void Eat()
{
    foreach (var dessert in GetDesserts())
    {
        dessert.icecream.AddTopping(dessert.topping);
        dessert.Eat();
    }
}
Daniel Earwicker
la source
En règle générale, ce que j'aimerais voir serait que .net définisse une norme pour quelques types spéciaux de types anonymes, de sorte que, par exemple struct var SimpleStruct {int x, int y;}, définirait une structure avec un nom commençant par un guid associé à des structures simples et a quelque chose comme {System.Int16 x}{System.Int16 y}ajouté; tout nom commençant par ce GUID serait nécessaire pour représenter une structure contenant uniquement ces éléments et le contenu spécifié particulier; si plusieurs définitions pour le même nom sont dans la portée et qu'elles correspondent, toutes seraient considérées du même type.
supercat
Une telle chose serait utile pour quelques types de types, y compris les classes et structures mutables et immuables ainsi que les interfaces et les délégués à utiliser dans des situations où la structure correspondante devrait être considérée comme impliquant une sémantique correspondante. Bien qu'il y ait certainement des raisons pour lesquelles il peut être utile que deux types de délégués qui ont les mêmes paramètres ne soient pas considérés comme interchangeables, il serait également utile de spécifier qu'une méthode veut un délégué qui prend une combinaison de paramètres mais au-delà de cela ne le fait pas Peu importe quel genre de délégué il s'agit.
supercat
Il est malheureux que si deux personnes différentes veulent écrire des fonctions qui prennent comme délégués d'entrée qui ont besoin d'un seul refparamètre, la seule façon dont il sera possible d'avoir un délégué qui peut être passé aux deux fonctions sera si une personne produit et compile un déléguez le type et le donne à l'autre pour construire. Il est impossible que les deux personnes puissent indiquer que les deux types doivent être considérés comme synonymes.
supercat
Avez-vous des exemples plus concrets où vous utiliseriez des classes anonymes plutôt que Tuple? Je viens de parcourir 50 endroits dans ma base de code où j'utilise des tuples, et tous sont soit des valeurs de retour (généralement yield return), soit des éléments de collections qui sont utilisés ailleurs, donc n'allez pas pour les classes anonymes.
2
@JonofAllTrades - les opinions varient probablement à ce sujet, mais j'essaie de concevoir les méthodes publiques comme si elles allaient être utilisées par quelqu'un d'autre, même si ce quelqu'un est moi, donc je me donne un bon service client! Vous avez tendance à appeler une fonction plus de fois que vous ne l'écrivez. :)
Daniel Earwicker
8

Semblable au mot var- clé , il est conçu comme une commodité - mais il est aussi facile d'en abuser.

À mon avis le plus humble, ne pas exposer Tuplecomme une classe de retour. Utilisez-le en privé, si la structure de données d'un service ou d'un composant l'exige, mais retournez des classes bien formées bien connues à partir de méthodes publiques.

// one possible use of tuple within a private context. would never
// return an opaque non-descript instance as a result, but useful
// when scope is known [ie private] and implementation intimacy is
// expected
public class WorkflowHost
{
    // a map of uri's to a workflow service definition 
    // and workflow service instance. By convention, first
    // element of tuple is definition, second element is
    // instance
    private Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> _map = 
        new Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> ();
}
johnny g
la source
2
Les langages "RAD" traditionnels (Java est le meilleur exemple) ont toujours choisi la sécurité et d'éviter de se tirer une balle dans les scénarios de type pied. Je suis heureux que Microsoft prenne des risques avec C # et donne au langage une belle puissance, même s'il peut être mal utilisé.
Matt Greer
4
Le mot-clé var n'est pas possible d'abuser. Peut-être vouliez-vous dire dynamique?
Chris Marisic
@Chris Marisic, juste pour clarifier, je ne voulais pas dire dans le même scénario - vous avez absolument raison, varne pouvez pas être renvoyé ou exister en dehors de sa portée déclarée. cependant, il est toujours possible de l'utiliser au- delà de son usage prévu et d'être «abusé»
johnny g
5
Je me tiens toujours sur cette période ne peut pas être abusée. C'est simplement un mot-clé pour faire une définition de variable plus courte. Votre argument porte peut-être sur les types anonymes, mais même ceux-ci ne peuvent vraiment pas être abusés car ils sont toujours des types liés statiquement normaux. Maintenant, la dynamique est une tout autre histoire.
Chris Marisic
4
var peut être abusé dans le sens où s'il est surutilisé, il peut parfois causer des problèmes à la personne qui lit le code. Surtout si vous n'êtes pas dans Visual Studio et que vous manquez d'intellisense.
Matt Greer
5

Utiliser une classe comme ResultTypeest plus clair. Vous pouvez donner des noms significatifs aux champs de la classe (alors qu'avec un tuple, ils seraient appelés Item1et Item2). Ceci est d'autant plus important si les types des deux champs sont les mêmes: le nom les distingue clairement.

Richard Fearn
la source
Un petit avantage supplémentaire: vous pouvez réorganiser en toute sécurité les paramètres d'une classe. Faire ainsi pour un tuple cassera le code, et si les champs ont des types similaires, cela peut ne pas être détectable au moment de la compilation.
Je suis d'accord, les tuples sont utilisés lorsqu'un développeur manque d'énergie pour penser à un nom de classe significatif regroupant des noms de propriété significatifs. La programmation est une question de communication. Les tuples sont un antipatron de la communication. J'aurais préféré que Microsoft le laisse en dehors du langage pour obliger les développeurs à prendre de bonnes décisions de conception.
mike gold
5

Que diriez-vous d'utiliser des tuples dans un motif décorer-trier-non décorer? (Transformée Schwartzian pour le peuple Perl). Voici un exemple artificiel, bien sûr, mais les tuples semblent être un bon moyen de gérer ce genre de chose:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] files = Directory.GetFiles("C:\\Windows")
                    .Select(x => new Tuple<string, string>(x, FirstLine(x)))
                    .OrderBy(x => x.Item2)
                    .Select(x => x.Item1).ToArray();
        }
        static string FirstLine(string path)
        {
            using (TextReader tr = new StreamReader(
                        File.Open(path, FileMode.Open)))
            {
                return tr.ReadLine();
            }
        }
    }
}

Maintenant, j'aurais pu utiliser un Object [] de deux éléments ou dans cet exemple spécifique une chaîne [] de deux éléments. Le fait est que j'aurais pu utiliser n'importe quoi comme deuxième élément d'un Tuple qui est utilisé en interne et est assez facile à lire.

Clinton Pierce
la source
3
Vous pouvez utiliser Tuple.Create au lieu du constructeur. C'est plus court.
Kugel le
un type anonyme sera beaucoup plus lisible; comme utiliser de vrais noms de variables au lieu de 'x'
Dave Cousineau
Ce serait maintenant . C'est un problème SO, les réponses publiées il y a des années et des années ne sont jamais nettoyées ou mises à jour pour les nouvelles technologies.
Clinton Pierce
4

IMO ces "tuples" sont essentiellement tous les structtypes anonymes d'accès public avec des membres non nommés .

Le seul endroit où j'utiliserais tuple est lorsque vous avez besoin de rassembler rapidement des données, dans une portée très limitée. La sémantique des données doit être évidente , donc le code n'est pas difficile à lire. Donc, utiliser un tuple ( int, int) pour (row, col) semble raisonnable. Mais j'ai du mal à trouver un avantage sur un structavec des membres nommés (donc aucune erreur n'est commise et les lignes / colonnes ne sont pas accidentellement interchangées)

Si vous renvoyez des données à l'appelant ou acceptez les données d'un appelant, vous devriez vraiment utiliser un structavec des membres nommés.

Prenons un exemple simple:

struct Color{ float r,g,b,a ; }
public void setColor( Color color )
{
}

La version tuple

public void setColor( Tuple<float,float,float,float> color )
{
  // why?
}

Je ne vois aucun avantage à utiliser tuple à la place d'une structure avec des membres nommés. L'utilisation de membres sans nom est un pas en arrière pour la lisibilité et la compréhensibilité de votre code.

Tuple me semble être un moyen paresseux d'éviter de créer un structavec des membres nommés réels. La surutilisation de tuple, où vous sentez vraiment que vous / ou quelqu'un d'autre rencontrant votre code aurait besoin de membres nommés est A Bad Thing ™ si jamais j'en ai vu un.

bobobobo
la source
3

Ne me jugez pas, je ne suis pas un expert, mais avec les nouveaux tuples en C # 7.x maintenant, vous pouvez retourner quelque chose comme:

return (string Name1, int Name2)

Au moins maintenant, vous pouvez le nommer et les développeurs peuvent voir des informations.

Denis Gordin
la source
2

Cela dépend, bien sûr! Comme vous l'avez dit, un tuple peut vous faire gagner du code et du temps lorsque vous souhaitez regrouper certains éléments pour une consommation locale. Vous pouvez également les utiliser pour créer des algorithmes de traitement plus génériques que si vous transmettez une classe concrète. Je ne me souviens pas combien de fois j'ai souhaité avoir quelque chose au-delà de KeyValuePair ou d'un DataRow pour passer rapidement une date d'une méthode à une autre.

D'un autre côté, il est tout à fait possible d'en faire trop et de faire passer des tuples où vous ne pouvez que deviner ce qu'ils contiennent. Si vous envisagez d'utiliser un tuple entre les classes, il serait peut-être préférable de créer une classe concrète.

Utilisés avec modération bien sûr, les tuples peuvent conduire à un code plus concis et plus lisible. Vous pouvez consulter C ++, STL et Boost pour des exemples de la façon dont les tuples sont utilisés dans d'autres langages, mais à la fin, nous devrons tous expérimenter pour trouver comment ils s'intègrent le mieux dans l'environnement .NET.

Panagiotis Kanavos
la source
1

Les tuples sont une fonctionnalité de framework inutile dans .NET 4. Je pense qu'une grande opportunité a été manquée avec C # 4.0. J'aurais aimé avoir des tuples avec des membres nommés, afin que vous puissiez accéder aux différents champs d'un tuple par nom au lieu de Value1 , Value2 , etc ...

Cela aurait nécessité un changement de langue (syntaxe), mais cela aurait été très utile.

Philippe Leybaert
la source
En quoi les tuples sont-ils une «fonctionnalité de langage»? C'est une classe disponible pour toutes les langues .net, n'est-ce pas?
Jason Webb
11
Relativement inutile en C #, peut-être. Mais System.Tuple n'a pas été ajouté au framework à cause de C #. Il a été ajouté pour faciliter l'interopérabilité entre F # et d'autres langages.
Joel Mueller
@Jason: Je n'ai pas dit que c'était une fonctionnalité de langage (je l'ai mal saisi, mais je l'ai corrigé avant que vous ne fassiez ce commentaire).
Philippe Leybaert
2
@Jason - les langages avec prise en charge directe des tuples ont un support implicite pour la déconstruction des tuples dans leurs valeurs de composant. Le code écrit dans ces langues n'accède généralement jamais, jamais, aux propriétés Item1, Item2. let success, value = MethodThatReturnsATuple()
Joel Mueller
@Joel: cette question est étiquetée comme C #, donc il s'agit en quelque sorte de C #. Je pense toujours qu'ils auraient pu en faire une fonctionnalité de première classe dans la langue.
Philippe Leybaert
1

Personnellement, je n'utiliserais jamais un Tuple comme type de retour car il n'y a aucune indication de ce que les valeurs représentent. Les tuples ont des utilisations intéressantes car contrairement aux objets, ils sont des types valeur et comprennent donc l'égalité. Pour cette raison, je les utiliserai comme clés de dictionnaire si j'ai besoin d'une clé multipartie ou comme clé pour une clause GroupBy si je veux grouper par plusieurs variables et ne veux pas de regroupements imbriqués (qui veut des groupements imbriqués?). Pour surmonter le problème avec une verbosité extrême, vous pouvez les créer avec une méthode d'assistance. Gardez à l'esprit que si vous accédez fréquemment à des membres (via Item1, Item2, etc.), vous devriez probablement utiliser une construction différente telle qu'une structure ou une classe anonyme.

Seth Paulson
la source
0

J'ai utilisé des tuples, le Tupleet le nouveau ValueTuple, dans un certain nombre de scénarios différents et suis arrivé à la conclusion suivante: ne pas utiliser .

À chaque fois, j'ai rencontré les problèmes suivants:

  • le code est devenu illisible en raison du manque de dénomination forte;
  • impossible d'utiliser les fonctionnalités de hiérarchie de classes, telles que les DTO de classe de base et les DTO de classe enfant, etc.
  • si elles sont utilisées à plusieurs endroits, vous finissez par copier et coller ces vilaines définitions, au lieu d'un nom de classe propre.

Mon avis est que les tuples sont un détriment, pas une fonctionnalité, de C #.

J'ai des critiques quelque peu similaires, mais beaucoup moins sévères, sur Func<>et Action<>. Ceux-ci sont utiles dans de nombreuses situations, en particulier les simples Actionet les Func<type>variantes, mais au-delà de cela, j'ai trouvé que la création d'un type de délégué est plus élégante, lisible, maintenable et vous donne plus de fonctionnalités, telles que ref/ outparameters.

M. TA
la source
J'ai mentionné les tuples nommés - ValueTuple- et je ne les aime pas non plus. Premièrement, la dénomination n'est pas forte, c'est plutôt une suggestion, très facile à gâcher car elle peut être attribuée implicitement à l'un Tupleou l' autre ou ValueTupleavec le même nombre et les mêmes types d'éléments. Deuxièmement, le manque d'héritage et la nécessité de copier-coller l'ensemble de la définition d'un endroit à l'autre sont toujours des inconvénients.
M. TA
Je suis d'accord avec ces points. J'essaie de n'utiliser Tuples que lorsque je contrôle le producteur et le consommateur, et s'ils ne sont pas trop "loin". Sens, producteur et consommateur dans la même méthode = «proche», alors que producteur et consommateur dans des assemblages différents = «à des années-lumière». Donc, si je crée des tuples au début d'une méthode et que je les utilise à la fin? Bien sûr, je suis d'accord avec ça. Je documente également les termes et autres. Mais oui, je suis d'accord que généralement ce n'est pas le bon choix.
Mike Christiansen