Question

Je me trouve parfois dans C # 3.0 à la recherche de moyens de simuler la notion de tuple. Au fil du temps, j'ai eu divers "pauvres homme". implémentations, en voici quelques unes:

Tableau d'objets de base :

object[] poorTuple = new object[]{foo,bar,baz}; // basic object array

Plus fortement typé , HoHoHo ...

KeyValuePair<TypeA, KeyValuePair<TypeB, TypeC>> poorTuple;

Implémentation d'une classe pouvant utiliser l'inférence de type (extraite de la programmation fonctionnelle de la Monde réel )

public static class Tuple{
  public static Tuple<T1, T2> Create<T1 foo, T2 bar>{
    return new Tuple<T1, T2>(foo, bar);
  }
}
// later: 
var data = Tuple.Create("foo", 42);

Questions:

  1. Tout autre moyen d'avoir un tuple de pauvre en C # 3.0 (ou une langue de choix sans structure de données).

  2. Quel est le meilleur moyen d'obtenir un tuple en C # 3.0 - si quelqu'un a une recommandation de bibliothèque, c'est la bienvenue.

  3. À quel moment (oui, généraliser pour moi) est-il logique de créer un type spécifique plutôt que quelque chose comme une liste ou un tuple? (recherche de règles empiriques)

Était-ce utile?

La solution

Vous pouvez créer des types anonymes qui fonctionnent de la même manière que les tuples, à l'exception des noms utiles:

var itemsWithChildCounts 
    = myObjects.Select(x => new { Name = x.Name, Count = x.Children.Count() });

Autres conseils

Voici le code d'un tuple générique tiré de article dans l'édition d'avril 2007 de Visual Studio Magazine .

public struct Tuple<T1, T2> : IEquatable<Tuple<T1, T2>>
{
    private readonly T1 first;
    public T1 First
    {
        get { return first; }
    }

    private readonly T2 second;
    public T2 Second
    {
        get { return second; }
    } 

    public Tuple(T1 f, T2 s)
    {
        first = f;
        second = s;
    }

    #region IEquatable<Tuple<T1,T2>> Members
    public bool Equals(Tuple<T1, T2> other)
    {
        return first.Equals(other.first) && 
            second.Equals(other.second);
    }

    public override bool Equals(object obj)
    {
        if (obj is Tuple<T1, T2>)
            return this.Equals((Tuple<T1, T2>)obj);
        else
            return false;
    }

    public override int GetHashCode()
    {
        return first.GetHashCode() ˆ second.GetHashCode();
    }
    #endregion
}

Pour 1 - 2: je préfère implémenter votre propre classe de tuple. L'implémentation que vous avez volée est décente. Cela devrait bien fonctionner.

Pour 3: Voici ma règle générale - Dès que vous allez réutiliser cette fonctionnalité dans plusieurs méthodes (avec les mêmes types ayant la même signification), ou si vous l'utilisez dans une API publique, je pense que c'est Il est temps de mettre en œuvre un " réel " classe avec vos types spécifiques.

  1. Le " Implémentation d'une classe " La méthode est aussi bonne qu'elle va l'être (et cela devrait être dans la prochaine version de .NET de toute façon)
  2. Aucune idée, je les garde dans ma propre bibliothèque de cours pour l'instant.
  3. J'envisagerais de créer une classe appropriée pour eux dès qu'ils seront exposés au public (c'est-à-dire lorsqu'ils ne seront plus utilisés uniquement pour stocker des valeurs associées pour une classe en interne).

Puisque vous avez demandé un avis, le mien serait de toujours créer un type - je ne peux pas trouver une raison pour ne pas le faire.

Le plus souvent, vous pouvez constater que vous aviez réellement besoin du type (l'utilisation principale est soit de stocker deux éléments dans une collection, soit de renvoyer deux éléments à partir d'un appel de méthode - dans les deux cas, si les éléments ne sont pas étroitement liés , vous faites probablement quelque chose de mal).

Je pense qu'il est bon de créer un nouveau type lorsqu'il est logique d'introduire un nouvel ensemble de valeurs dans votre programme. Par exemple, si vous écrivez une calculatrice complexe, créez un type de nombre complexe. Si vous voulez vraiment "coller" quelques variables ensemble pour un moment, puis un tuple est probablement un meilleur choix. Supposons que vous ayez une fonction simple qui rassemble deux nombres à partir de la console ... vous pourriez faire quelque chose comme:

static void GetNumbers(out int x, out int y) { ... }
...
int x, y;
GetNumbers(out x, out y);

Je pense que cela a généralement du sens quand un "getter" function a une valeur de retour mais dans ce cas, elle ne l’a pas car je ne peux pas vraiment avoir deux valeurs de retour. Je pourrais créer un nouveau type appelé TwoNumbers et l'utiliser, mais je pense que cela devient rapidement plus un problème qu'une solution. Si C # avait des nuplets, je pourrais peut-être faire quelque chose comme ce qui suit:

static (int, int) GetNumbers() { ... }
...
int x, y;
(x, y) = GetNumbers();

Maintenant, la question vraiment intéressante est: bien que C # n’ait pas cette fonctionnalité, puis-je l’implémenter moi-même avec une bibliothèque? Le code que vous suggérez est un début mais ne me permet pas d’attribuer comme je l’ai fait dans le deuxième exemple. Je ne suis pas sûr de C #, mais vous pouvez vous en approcher en utilisant le fait que un appel de fonction peut être l'opérande de gauche de l'opérateur d'affectation lorsque sa valeur de retour est un type de référence . Considérez ce qui suit:

// this class is implemented much like yours only with C++
template<typename T1, typename T2> class tuple { ... }
...
template<typename T1, typename T2> tuple<T1, T2>& tie(T1 a, T2 b) { ... }
...
template<typename T1, typename T2> tuple<T1, T2> get_numbers() { ... }
...
int x, y;
tie(x, y) = get_numbers();

Je dirais que c'est sacrément proche ... au lieu de (x, y) = , nous avons tie (x, y) = . Si vous êtes intéressé par les détails de la mise en œuvre, je vous renverrai à la bibliothèque TR1 où je l’ai appris pour la première fois:

http: //www.boost .org / doc / libs / 1_41_0 / libs / tuple / doc / tuple_users_guide.html # tiers

Donc, pour ramener tout cela en C # 3.0 ... nous pouvons certainement créer une classe de tuple générique, comme vous l'avez montré, mais pouvons-nous créer une fonction telle que tie to "unpack" le tuple en C #? Je ne l'ai pas essayé, ça a l'air amusant. Sans quelque chose comme ça, je serais réticent à laisser une bibliothèque de tuples C # proliférer dans mon code.

Je n'aime pas l'inférence de type en C # car on en abuse trop pour une écriture plus courte. Bien sûr, c’est une fonctionnalité très intéressante, mais les gens en abusent à mon humble avis, comme dans ce cas.

Dans ce cas, je spécifierais explicitement le type pour éviter toute confusion sur le type (c'est-à-dire que 42 est peut-être un long, un octet ou un court).

Alors pourquoi ne pas avoir une simple classe de tuple, qui peut être implémentée en quelques lignes. Et si vous êtes paresseux, vous pouvez même écrire des méthodes d’extension pour votre classe de tuple. Cela rend la vie plus facile mais aussi plus propre.

Ne voyez pas l’intérêt d’avoir un " fantaisie " tuple class au lieu du générique que vous avez présenté (sauf pour l'inférence de type).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top