Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Wählen Sie zwischen anonymen Typen System.Tuple<T1,T2>und System.ValueTuple<T1,T2> basierend auf Benutzerfreundlichkeit, Leistung und Kompromissen.
ValueTuple bietet einen Werttyp mit der Flexibilität anonymer Typen. In diesem Artikel wird erläutert, wann jeder Typ ausgewählt werden soll.
Nutzbarkeit und Funktionalität
Mit Language-Integrated Query (LINQ) projizieren Sie häufig Abfrageergebnisse in anonymen Typen, die einige ausgewählte Eigenschaften aus den Quellobjekten enthalten. Im folgenden Beispiel wird ein Array von DateTime Objekten instanziiert und jedes Objekt in einen anonymen Typ mit zwei Eigenschaften projiziert.
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var anonymous in
dates.Select(
date => new { Formatted = $"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks }))
{
Console.WriteLine($"Ticks: {anonymous.Ticks}, formatted: {anonymous.Formatted}");
}
Anonyme Typen werden mithilfe des new Operators instanziiert, und die Eigenschaftennamen und -typen werden aus der Deklaration abgeleitet. Wenn zwei oder mehr anonyme Objektinitialisierer in derselben Assembly eine Abfolge von Eigenschaften in derselben Reihenfolge angeben und dieselben Namen und Typen aufweisen, behandelt der Compiler die Objekte als Instanzen desselben Typs. Sie erhalten die gleichen vom Compiler generierten Typinformationen.
Der vorherige C#-Codeausschnitt projektiert einen anonymen Typ mit zwei Eigenschaften, ähnlich wie die folgende vom Compiler generierte C#-Klasse:
internal sealed class f__AnonymousType0
{
public string Formatted { get; }
public long Ticks { get; }
public f__AnonymousType0(string formatted, long ticks)
{
Formatted = formatted;
Ticks = ticks;
}
}
Weitere Informationen finden Sie unter anonymen Typen. Beim Projizieren in LINQ-Abfragen steht dieselbe Funktionalität mit Tupeln zur Verfügung. Sie können Eigenschaften in Tupel projizieren. Diese Tupel verlaufen genauso durch die Abfrage wie anonyme Typen. Sehen Sie sich nun das folgende Beispiel an, in dem System.Tuple<string, long> verwendet wird.
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var tuple in
dates.Select(
date => new Tuple<string, long>($"{date:MMM dd, yyyy hh:mm zzz}", date.Ticks)))
{
Console.WriteLine($"Ticks: {tuple.Item2}, formatted: {tuple.Item1}");
}
Mit der System.Tuple<T1,T2>-Instanz werden nummerierte Elementeigenschaften wie Item1 und Item2 bereitgestellt. Durch diese Eigenschaftsnamen kann es schwieriger werden, die Absicht der Eigenschaftswerte nachzuvollziehen, da der Eigenschaftsname nur die Ordnungszahl bereitstellt. Darüber hinaus sind die System.Tuple Typen Referenztypen class . Dies System.ValueTuple<T1,T2> ist jedoch ein Werttyp struct . Im folgenden C#-Codeausschnitt wird ValueTuple<string, long> als Ziel für die Projektion verwendet. Dabei wird eine Literalsyntax zugewiesen.
var dates = new[]
{
DateTime.UtcNow.AddHours(-1),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(1),
};
foreach (var (formatted, ticks) in
dates.Select(
date => (Formatted: $"{date:MMM dd, yyyy at hh:mm zzz}", date.Ticks)))
{
Console.WriteLine($"Ticks: {ticks}, formatted: {formatted}");
}
Weitere Informationen zu Tupeln finden Sie unter Tuple-Typen (C#-Referenz) oder Tuples (Visual Basic).
Die vorherigen Beispiele sind alle funktional gleichwertig, es gibt jedoch geringfügige Unterschiede bei der Benutzerfreundlichkeit und den zugrunde liegenden Implementierungen.
Kompromisse
Sie möchten möglicherweise immer ValueTuple anstelle von Tuple und anonymen Typen verwenden, aber es gibt Kompromisse, die Sie berücksichtigen sollten. Die ValueTuple-Typen sind änderbar, während Tuple-Typen schreibgeschützt sind. Anonyme Typen können in Ausdrucksbaumstrukturen verwendet werden. Tupel eignen sich nicht dafür. Die folgende Tabelle enthält eine Übersicht über einige der wichtigsten Unterschiede.
Wichtige Unterschiede
| Name | Zugriffsmodifizierer | Typ | Name des benutzerdefinierten Mitglieds | Unterstützung der Dekonstruktion | Unterstützung der Ausdrucksbaumstruktur |
|---|---|---|---|---|---|
| Anonyme Typen | internal |
class |
✔️ | ❌ | ✔️ |
| Tuple | public |
class |
❌ | ❌ | ✔️ |
| ValueTuple | public |
struct |
✔️ | ✔️ | ❌ |
Serialisierung
Ein wichtiger Aspekt bei der Auswahl eines Typs ist, ob er serialisiert werden muss. Serialisierung ist der Prozess der Konvertierung des Zustands eines Objekts in eine Form, die beibehalten oder transportiert werden kann. Weitere Informationen finden Sie unter Serialisierung. Wenn die Serialisierung wichtig ist, ist das Erstellen eines class oder struct gegenüber anonymen Typen oder Tupeltypen zu bevorzugen.
Leistung
Die Leistung zwischen diesen Typen hängt vom Szenario ab. Die wesentlichen Auswirkungen betreffen den Kompromiss zwischen Zuteilungen und Kopieren. In den meisten Szenarien ist die Auswirkung klein. Wenn erhebliche Auswirkungen auftreten könnten, sollten Messungen getroffen werden, um die Entscheidung zu informieren.
Schlussfolgerung
Wenn Sie als Entwickler zwischen Tupeln und anonymen Typen auswählen müssen, sollten Sie verschiedene Faktoren berücksichtigen. Wenn Sie im Allgemeinen nicht mit Ausdrucksstrukturen arbeiten und mit der Tupel-Syntax vertraut sind, wählen Sie ValueTuple aus, da sie einen Werttyp mit der Flexibilität zum Benennen von Eigenschaften bereitstellen. Wenn Sie mit Ausdrucksstrukturen arbeiten und Eigenschaften benennen möchten, wählen Sie anonyme Typen aus. Verwenden Sie andernfalls Tuple.