Quelle est la meilleure façon d'utiliser une paire (triple, etc.) comme une valeur unique en C #?

StackOverflow https://stackoverflow.com/questions/101825

Question

C'est-à-dire, j'aimerais avoir un tuple de valeurs.

Le cas d'utilisation qui me préoccupe:

Dictionary<Pair<string, int>, object>

ou

Dictionary<Triple<string, int, int>, object>

Existe-t-il des types intégrés tels que Pair ou Triple? Ou quel est le meilleur moyen de le mettre en œuvre?

Mettre à jour Certaines réponses à une implémentation générale de tuples, mais pour les tuples utilisées comme clés dans les dictionnaires, vous devez également vérifier le calcul correct du code de hachage. Quelques informations supplémentaires à ce sujet dans une autre question .

Mise à jour 2 Je suppose qu'il est également bon de rappeler que, lorsque vous utilisez une valeur comme clé dans le dictionnaire, elle doit être immuable.

Était-ce utile?

La solution

J'ai implémenté une bibliothèque de tuple en C #. Visitez http://www.adventuresinsoftware.com/generics/ et cliquez sur &. tuples " lien.

Autres conseils

Classes intégrées

Dans certains cas spécifiques, le framework .net fournit déjà des classes de type tuple que vous pourrez peut-être exploiter.

Paires et triples

Le générique System.Collections.Generic.KeyValuePair La classe peut être utilisée comme implémentation d'une paire adhoc C'est la classe que le Le dictionnaire générique utilise en interne.

Vous pouvez également vous débrouiller avec le System.Collections.DictionaryEntry structure qui agit comme un couple rudimentaire et a l'avantage de être disponible dans mscorlib. L’inconvénient est que cette structure n’est pas fortement typé.

Les paires et les triples sont également disponibles sous forme de System.Web.UI.Pair et System.Web.UI.Triplet classes. Même si ces classes vivent dans l'assembly System.Web ils pourraient parfaitement convenir au développement de winforms. Cependant, ces classes sont pas fortement typé non plus et pourrait ne pas convenir dans certains scénarios, tels qu'un cadre général ou une bibliothèque.

Les tuples d'ordre supérieur

Pour les n-uplets d'ordre supérieur, à moins de rouler votre propre classe, il peut ne pas être une solution simple.

Si vous avez installé le langage F # , vous pouvez référencer le FSharp.Core.dll qui contient un ensemble de génériques immuables Microsoft.Fsharp.Core.Tuple classe jusqu'à des sextuples génériques. Cependant, même si un FSharp.Code.dll non modifié peut être redistribué, F # est un langage de recherche et un travail en cours afin cette solution ne devrait intéresser que les milieux académiques.

Si vous ne voulez pas créer votre propre classe et que vous êtes mal à l'aise référant à la bibliothèque F #, une astuce intéressante pourrait consister à étendre la classe générique KeyValuePair afin que le membre Value soit lui-même un KeyValuePair imbriqué.

Par exemple, le code suivant illustre comment vous pouvez exploiter le KeyValuePair afin de créer un Triplé:

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

Ceci permet d’étendre la classe à n’importe quel niveau arbitraire selon les besoins.

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string> quadruple =
    new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>();
KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string> quintuple =
    new KeyValuePair<KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string>, string>, string>();

Rouler le vôtre

Dans d’autres cas, vous devrez peut-être rouler vous-même. classe de tuple, et ce n'est pas difficile.

Vous pouvez créer des structures simples comme ceci:

struct Pair<T, R>
{
    private T first_;
    private R second_;

    public T First
    {
        get { return first_; }
        set { first_ = value; }
    }

    public R Second
    {
        get { return second_; }
        set { second_ = value; }
    }
}

Structures et bibliothèques

Ce problème a déjà été abordé et les cadres généraux existe. Vous trouverez ci-dessous un lien vers l'un de ces cadres:

public struct Pair<T1, T2>
{
    public T1 First;
    public T2 Second;
}

public struct Triple<T1, T2, T3>
{
    public T1 First;
    public T2 Second;
    public T3 Third;
}

Avance rapide vers 2010, .NET 4.0 prend désormais en charge les n-uplets d'arbitraire n . Ces tuples implémentent l'égalité structurelle et la comparaison comme prévu.

Pair et Triplet sont des classes existantes dans .net, voir msdn:

Triplet

Pair

Je les ai récemment rencontrés en jouant avec le décodage de viewstate

Habituellement, je crée simplement ma propre structure, contenant les valeurs. C'est souvent un peu plus lisible;)

KeyValuePair est la meilleure classe à étendre si vous ne souhaitez pas créer vos propres classes.

int id = 33;
string description = "This is a custom solution";
DateTime created = DateTime.Now;

KeyValuePair<int, KeyValuePair<string, DateTime>> triple =
   new KeyValuePair<int, KeyValuePair<string, DateTime>>();
triple.Key = id;
triple.Value.Key = description;
triple.Value.Value = created;

Vous pouvez l'étendre à autant de niveaux que vous le souhaitez.

KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string> quadruple =
   new KeyValuePair<KeyValuePair<KeyValuePair<string, string>, string, string>();

Remarque : les classes Triplet et Paire existent dans la System.Web -dll. très approprié pour d’autres solutions que ASP.NET.

Vous pouvez créer assez facilement vos propres classes de tuples. La seule chose qui risque de devenir gênante est votre substitution d'égalité et de hashcode (indispensable si vous allez les utiliser dans des dictionnaires).

Il convient de noter que la structure KeyValuePair<TKey,TValue> propre à .Net a méthodes relativement lentes d’égalité et de hachage .

En supposant que cela ne vous préoccupe pas, il reste que le code est difficile à comprendre:

public Tuple<int, string, int> GetSomething() 
{
    //do stuff to get your multi-value return
}

//then call it:
var retVal = GetSomething();

//problem is what does this mean?
retVal.Item1 / retVal.Item3; 
//what are item 1 and 3?

Dans la plupart des cas, il est plus facile de créer une classe d'enregistrement spécifique (au moins jusqu'à ce que C # 4 rende ce magicien du compilateur)

class CustomRetVal {
    int CurrentIndex { get; set; }
    string Message { get; set; }
    int CurrentTotal { get; set; }
}

var retVal = GetSomething();

//get % progress
retVal.CurrentIndex / retVal.CurrentTotal;

Une solution simple n'a pas encore été mentionnée. Vous pouvez aussi simplement utiliser un List<T>. Il est intégré, efficace et facile à utiliser. Certes, ça a l'air un peu bizarre au début, mais ça fait parfaitement son travail, surtout pour un plus grand nombre d'éléments.

NGenerics - la célèbre bibliothèque d’algorithmes et de structures de données .Net, a récemment introduit des structures de données immuables dans son ensemble.

Les premières classes immuables à implémenter étaient les classes paire et tuple . Le code est bien couvert d'essais et est assez élégant. Vous pouvez le vérifier ici . Ils travaillent actuellement sur les autres alternatives immuables et devraient être prêts sous peu.

Il n'y a pas d'éléments intégrés, mais une paire < T, R > la classe est triviale à créer.

Oui, il y a System.Web.UI.Pair et System.Web.UI.Triplet (qui a un créateur surchargé pour le comportement de type Pair!)

Pour le premier cas, j'utilise habituellement

Dictionary<KeyValuePair<string, int>, object>

Il n'y a pas de classes intégrées pour cela. Vous pouvez utiliser KeyValuePair ou déployer votre propre implémentation.

Vous pouvez utiliser System.Collections.Generic.KeyValuePair comme implémentation Pair.

Ou vous pouvez simplement mettre en œuvre le vôtre, ils ne sont pas difficiles:

public class Triple<T, U, V>
{
  public T First {get;set;}
  public U Second {get;set;}
  public V Third {get;set;}
}

Bien sûr, vous pouvez rencontrer un jour un problème pour lequel Triple (string, int, int) n’est pas compatible avec Triple (int, int, string). Peut-être aller avec System.Xml.Linq.XElement à la place.

Il y a aussi le tuple < > types en F #; il vous suffit de faire référence à FSharp.Core.dll.

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