Quelle est la meilleure façon d'utiliser une paire (triple, etc) de valeurs comme une seule valeur en C#?
C'est, j'aimerais avoir un n-uplet de valeurs.
Le cas d'utilisation dans mon esprit:
Dictionary<Pair<string, int>, object>
ou
Dictionary<Triple<string, int, int>, object>
y a-t-il des types intégrés comme paire ou Triple? Ou Quelle est la meilleure façon de le mettre en œuvre?
mise à Jour Il y a quelques usage général tuples implémentations décrites dans les réponses, mais tuples sont utilisés comme clés dans les dictionnaires, vous devez additionaly vérifier le calcul correct du code de hachage. Un peu plus d'info sur cela dans un autre question .
Update 2 je suppose qu'il est également intéressant de rappeler, que lorsque vous utilisez une valeur comme une clé dans le dictionnaire, il devrait être immuable.
16 réponses
j'ai implémenté une bibliothèque tuple en C#. Visite http://www.adventuresinsoftware.com/generics / et cliquez sur le lien" tuples".
Classes De Bâtiments
dans certains cas spécifiques, le framework .net fournit déjà des classes tuple-like que vous pourriez être en mesure d'exploiter.
couples et Triples
le générique du Système.Collection.Générique.KeyValuePair class pourrait être utilisé comme une implémentation de paire adhoc. C'est le de classe que l' Dictionnaire générique utilise en interne.
alternativement, vous pouvez être en mesure de faire avec le du Système.Collection.DictionaryEntry structure qui agit comme une paire rudimentaire et a l'avantage de disponible en mscorlib. Le côté négatif, cependant, est que cette structure n'est pas fortement typé.
Paires et Triples sont également disponibles sous la forme de la Système.Web.INTERFACE.Paire et du Système.Web.INTERFACE.Triplet classes. Même si ces classes vivent dans le système .Assemblage Web ils pourraient être parfaitement adaptés pour le développement de winforms. Toutefois, ces classes sont pas fortement tapé ni l'un ou l'autre et pourrait ne pas être approprié dans certains scénarios, comme un cadre général ou une bibliothèque.
ordre supérieur tuples
pour les tuples d'ordre supérieur, à moins de rouler votre propre classe, il peut ne soit pas une solution simple.
Si vous avez installé le F # language , vous pouvez faire référence au FSharp.Core.dll qui contient un ensemble de immuable Générique Microsoft.Fsharp.Core.Tuple classes jusqu'au sextuples Générique. Cependant, même si une non modifié FSharp.Code.dll peut être redistribué, F# est un langage de recherche et d'un travail en cours donc cette solution n'intéressera vraisemblablement que les milieux universitaires.
Si vous ne voulez pas créer votre propre classe et sont mal à l'aise en faisant référence à la bibliothèque F#, Une astuce pourrait consister à étendre la classe générique KeyValuePair de sorte que le membre de valeur soit lui-même un KeyValuePair imbriqué.
par exemple, le le code suivant illustre comment vous pouvez utiliser KeyValuePair afin de créer un triple:
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;
Cela permet d'étendre la classe à n'importe quel niveau est requis.
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 Propre
dans d'autres cas, vous pourriez avoir besoin de rouler votre propre classe 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; }
}
}
Frameworks et Bibliothèques
ce problème a déjà été abordé et les cadres d'usage général existent. Voici un lien vers un tel cadre:
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;
}
Fast-forward à 2010 .NET 4.0 prend désormais en charge n-tuples de l'arbitraire n . Ces tuples mettent en œuvre l'égalité structurelle et la comparaison comme prévu.
d'habitude je crée juste ma propre structure, contenant les valeurs. C'est souvent un peu plus lisible ;)
KeyValuePair est la meilleure classe à étendre si vous ne voulez 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>();
Note : les classes Triplet et paire existent à l'intérieur du système .Web - dll, de sorte qu'il n'est pas très adapté pour d'autres solutions que ASP.NET.
vous pouvez relativement facilement créer vos propres classes de tuple, la seule chose qui est potentiellement brouillon est votre égalité et les dérogations de hashcode (essentiel si vous allez les utiliser dans les dictionnaires).
il est à noter que la structure de .Net KeyValuePair<TKey,TValue>
a égalité relativement lente et méthodes hashcode .
en supposant que ce n'est pas un souci pour vous, Il ya encore le problème que le code finit par être difficile à figure:
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 de ces cas, je trouve plus facile de créer une classe d'enregistrement spécifique (au moins jusqu'à ce que C#4 fasse de ce compilateur-magic)
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 également utiliser un List<T>
. Il est intégré, efficace et facile à utiliser. Accordé, il semble un peu bizarre au premier abord, mais il fait son boulot parfaitement, surtout pour un plus grand nombre d'éléments.
NGenerics - le populaire .Net algorithmes et structures de données de la bibliothèque, a récemment introduit immuable structures de données à l'ensemble.
les premières immuables à mettre en œuvre étaient les classes pair et tuple . Le code est bien rempli de tests et est très élégant. Vous pouvez le vérifier ici . Ils travaillent actuellement sur les autres alternatives immuables et ils devraient être prêts d'ici peu.
il n'y a pas d'ins construit, mais une classe
Oui, il y a un système.Web.INTERFACE.La paire et le Système.Web.INTERFACE.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 le système.Collection.Générique.KeyValuePair que votre mise en œuvre de paire.
ou vous pouvez simplement mettre en œuvre votre propre, 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 pourriez un jour avoir un problème qui Triple(string, int, int) n'est pas compatible avec Triple(int, int, string). Peut-être aller avec un Système.XML.Linq.XElement à la place.
il y a aussi les types de Tuple dans F#; vous devez juste faire référence à FSharp.Core.DLL.