.Net 3.5 unterstützt keine Tupel. Schade, aber nicht sicher, ob die zukünftige Version von .net Tupel unterstützt oder nicht?
Antworten:
Ich habe gerade diesen Artikel aus dem MSDN Magazine gelesen: Building Tuple
Hier einige Auszüge:
Mit der kommenden Version 4.0 von Microsoft .NET Framework wird ein neuer Typ namens System.Tuple eingeführt. System.Tuple ist eine Sammlung heterogen typisierter Daten mit fester Größe.
Wie ein Array hat ein Tupel eine feste Größe, die nach seiner Erstellung nicht mehr geändert werden kann. Im Gegensatz zu einem Array kann jedes Element in einem Tupel ein anderer Typ sein, und ein Tupel kann eine starke Typisierung für jedes Element garantieren.
Es gibt bereits ein Beispiel für ein Tupel, das im Microsoft .NET Framework im System.Collections.Generic-Namespace schwebt: KeyValuePair. Während KeyValuePair als dasselbe wie Tuple angesehen werden kann, da beide Typen zwei Dinge enthalten, unterscheidet sich KeyValuePair von Tuple, da es eine Beziehung zwischen den beiden gespeicherten Werten hervorruft (und dies aus gutem Grund, da es die Dictionary-Klasse unterstützt ).
Darüber hinaus können Tupel beliebig dimensioniert werden, während KeyValuePair nur zwei Dinge enthält: einen Schlüssel und einen Wert.
Während einige Sprachen wie F # eine spezielle Syntax für Tupel haben, können Sie den neuen allgemeinen Tupeltyp aus jeder Sprache verwenden. Wenn wir uns das erste Beispiel noch einmal ansehen, können wir sehen, dass Tupel in Sprachen ohne Syntax für ein Tupel übermäßig ausführlich sein können, obwohl sie nützlich sind:
class Program {
static void Main(string[] args) {
Tuple<string, int> t = new Tuple<string, int>("Hello", 4);
PrintStringAndInt(t.Item1, t.Item2);
}
static void PrintStringAndInt(string s, int i) {
Console.WriteLine("{0} {1}", s, i);
}
}
Mit dem Schlüsselwort var aus C # 3.0 können wir die Typensignatur für die Tupelvariable entfernen, wodurch etwas besser lesbarer Code möglich ist.
var t = new Tuple<string, int>("Hello", 4);
Wir haben einer statischen Tupelklasse auch einige Factory-Methoden hinzugefügt, die es einfacher machen, Tupel in einer Sprache zu erstellen, die Typinferenz unterstützt, wie z. B. C #.
var t = Tuple.Create("Hello", 4);
#region tuples
public class Tuple<T>
{
public Tuple(T first)
{
First = first;
}
public T First { get; set; }
}
public class Tuple<T, T2> : Tuple<T>
{
public Tuple(T first, T2 second)
: base(first)
{
Second = second;
}
public T2 Second { get; set; }
}
public class Tuple<T, T2, T3> : Tuple<T, T2>
{
public Tuple(T first, T2 second, T3 third)
: base(first, second)
{
Third = third;
}
public T3 Third { get; set; }
}
public class Tuple<T, T2, T3, T4> : Tuple<T, T2, T3>
{
public Tuple(T first, T2 second, T3 third, T4 fourth)
: base(first, second, third)
{
Fourth = fourth;
}
public T4 Fourth { get; set; }
}
#endregion
Und um Erklärungen schöner zu machen:
public static class Tuple
{
//Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2")
public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2)
{
return new Tuple<T1, T2>(t1, t2);
}
//etc...
}
Tuple<T1,T2,T3>
als zu übergeben Tuple<T1,T2>
? Die Antwort ist wahrscheinlich nein.
In Lokad Shared Libraries (natürlich Open Source ) gibt es eine ordnungsgemäße (nicht schnelle) C # -Tupel- Implementierung , die die folgenden erforderlichen Funktionen enthält:
Das Implementieren von Tupelklassen oder das Wiederverwenden von F # -Klassen in C # ist nur die halbe Wahrheit - diese geben Ihnen die Möglichkeit, Tupel relativ einfach zu erstellen, aber nicht wirklich den syntaktischen Zucker, der sie in Sprachen wie F # so schön macht.
Zum Beispiel können Sie in F # Pattern Matching verwenden, um beide Teile eines Tupels innerhalb einer Let-Anweisung zu extrahieren, z
let (a, b) = someTupleFunc
Leider wäre es viel weniger elegant, dasselbe mit den F # -Klassen von C # zu tun:
Tuple<int,int> x = someTupleFunc();
int a = x.get_Item1();
int b = x.get_Item2();
Tupel stellen eine leistungsstarke Methode dar, um mehrere Werte aus einem Funktionsaufruf zurückzugeben, ohne dass Sie Ihren Code mit Wegwerfklassen verunreinigen oder auf hässliche ref- oder out-Parameter zurückgreifen müssen. Meiner Meinung nach sind sie jedoch ohne syntaktischen Zucker, um ihre Kreation und ihren Zugang eleganter zu gestalten, von begrenztem Nutzen.
Meiner Meinung nach ist die Funktion für anonyme Typen kein Tupel, sondern ein sehr ähnliches Konstrukt. Die Ausgabe einiger LINQ-Abfragen sind Sammlungen anonymer Typen, die sich wie Tupel verhalten.
Hier ist eine Aussage, die ein typisiertes Tupel erzeugt :-) on the fly:
var p1 = new {a = "A", b = 3};
Siehe: http://www.developer.com/net/csharp/article.php/3589916
C # 7 unterstützt Tupel nativ:
var unnamedTuple = ("Peter", 29);
var namedTuple = (Name: "Peter", Age: 29);
(string Name, double Age) typedTuple = ("Peter", 29);
ValueTuple
Strukturen enthalten. Sie können diese jedoch beispielsweise mithilfe eines NuGet-Pakets wie ValueTupleBridge bereitstellen .
Meine Open-Source-.NET- Sasa-Bibliothek enthält seit Jahren Tupel (zusammen mit vielen anderen Funktionen wie dem vollständigen MIME-Parsing). Ich benutze es jetzt seit ein paar Jahren im Produktionscode.
C # unterstützt einfache Tupel über Generika ganz einfach (gemäß einer früheren Antwort), und mit "Mumble Typing" (eine von vielen möglichen Verbesserungen der C # -Sprache) zur Verbesserung der Typinferenz können sie sehr, sehr leistungsfähig sein.
Für das, was es wert ist, unterstützt F # Tupel von Haus aus, und nachdem ich damit gespielt habe, bin ich mir nicht sicher, ob (anonyme) Tupel viel hinzufügen ... was Sie an Kürze gewinnen, verlieren Sie sehr schnell an Codeklarheit.
Für Code innerhalb einer einzelnen Methode gibt es anonyme Typen. Für Code, der außerhalb einer Methode liegt, halte ich mich an einfache benannte Typen. Wenn ein zukünftiges C # es einfacher macht, diese unveränderlich zu machen (obwohl es immer noch einfach ist, damit zu arbeiten), bin ich natürlich glücklich.
{ j = ErrorCode, h = ResultObj } = SomeFunction()
(wo j
und h
sind Einheimische) wäre viel hilfreicher gewesen als Tupel.
Hier sind meine Tupel, die von einem Python-Skript automatisch generiert werden. Ich bin also vielleicht etwas über Bord gegangen:
Link zum Subversion-Repository
Sie benötigen einen Benutzernamen / ein Passwort, beide sind Gast
Sie basieren auf Vererbung, werden jedoch Tuple<Int32,String>
nicht gleich verglichen, Tuple<Int32,String,Boolean>
selbst wenn sie zufällig dieselben Werte für die beiden ersten Mitglieder haben.
Sie implementieren auch GetHashCode und ToString usw. sowie viele kleinere Hilfsmethoden.
Anwendungsbeispiel:
Tuple<Int32, String> t1 = new Tuple<Int32, String>(10, "a");
Tuple<Int32, String, Boolean> t2 = new Tuple<Int32, String, Boolean>(10, "a", true);
if (t1.Equals(t2))
Console.Out.WriteLine(t1 + " == " + t2);
else
Console.Out.WriteLine(t1 + " != " + t2);
Wird ausgegeben:
10, a != 10, a, True
Tuple<Int32, String> t1 = new Tuple<Int32, String, Boolean>(10, "a", true);
usw. Ich bin mir nicht sicher, ob es ein Szenario gibt, das gewünscht wird.
Wenn ich mich richtig erinnere, sind Tupel nur Daten.
Wenn Sie gruppierte Daten möchten, erstellen Sie Klassen, die Eigenschaften enthalten. Wenn Sie so etwas wie das KeyValuePair benötigen, dann ist es da.
Ich wäre überrascht - C # ist eine stark typisierte Sprache, während Tupel für dynamisch typisierte Sprachen geeignet sind. C # hat sich im Laufe der Zeit dynamischer entwickelt, aber das ist syntaktischer Zucker, keine echte Verschiebung der zugrunde liegenden Datentypen.
Wenn Sie zwei Werte in einer Instanz möchten, ist ein KeyValuePair <> ein anständiger Ersatz, wenn auch ungeschickt. Sie können auch eine Struktur oder eine Klasse erstellen, die dasselbe tut und erweiterbar ist.
Um diese in einer Hashtabelle oder einem Wörterbuch nützlich zu machen, möchten Sie wahrscheinlich Überladungen für GetHashCode und Equals bereitstellen.