Volba mezi anonymními typy a typy řazené kolekce členů
Volba vhodného typu zahrnuje zvážení použitelnosti, výkonu a kompromisů v porovnání s jinými typy. Anonymní typy jsou k dispozici od verze C# 3.0, zatímco obecné System.Tuple<T1,T2> typy byly zavedeny v rozhraní .NET Framework 4.0. Od té doby byly zavedeny nové možnosti s podporou na úrovni jazyka, například System.ValueTuple<T1,T2> – což jak název napovídá, poskytují typ hodnoty s flexibilitou anonymních typů. V tomto článku se dozvíte, kdy je vhodné zvolit jeden typ nad druhým.
Použitelnost a funkce
Anonymní typy byly zavedeny v jazyce C# 3.0 s výrazy LINQ (Language-Integrated Query). U LINQ vývojáři často projektují výsledky dotazů do anonymních typů, které obsahují několik vybraných vlastností z objektů, se kterými pracují. Představte si následující příklad, který vytvoří instanci pole DateTime objektů a iteruje je projektováním do anonymního typu se dvěma vlastnostmi.
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}");
}
Anonymní typy se vytvoří instance pomocí operátoru new
a názvy a typy vlastností jsou odvozeny z deklarace. Pokud dva nebo více anonymních inicializátorů objektů ve stejném sestavení určují posloupnost vlastností, které jsou ve stejném pořadí a mají stejné názvy a typy, kompilátor zachází s objekty jako s instancemi stejného typu. Sdílejí stejné informace o typu generovaném kompilátorem.
Předchozí fragment kódu jazyka C# projektuje anonymní typ se dvěma vlastnostmi, podobně jako následující třída jazyka C#vygenerovaná kompilátorem:
internal sealed class f__AnonymousType0
{
public string Formatted { get; }
public long Ticks { get; }
public f__AnonymousType0(string formatted, long ticks)
{
Formatted = formatted;
Ticks = ticks;
}
}
Další informace naleznete v anonymních typech. Stejné funkce existují s řazenými kolekcemi členů při promítání do dotazů LINQ, můžete vybrat vlastnosti do řazených kolekcí členů. Tyto řazené kolekce členů procházejí dotazem stejně jako anonymní typy. Nyní zvažte následující příklad pomocí .System.Tuple<string, long>
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}");
}
System.Tuple<T1,T2>S , instance zveřejňuje číslovaný položky vlastnosti, například Item1
, a Item2
. Tyto názvy vlastností můžou ztížit pochopení záměru hodnot vlastností, protože název vlastnosti poskytuje pouze pořadové číslo. Kromě toho jsou typy System.Tuple
odkazy class
. Jedná se System.ValueTuple<T1,T2> však o typ hodnoty struct
. Následující fragment kódu jazyka C# se používá ValueTuple<string, long>
k projektu. Tím se přiřadí pomocí literální syntaxe.
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}");
}
Další informace o řazených kolekcí členů naleznete v tématu Typy řazené kolekce členů (referenční dokumentace jazyka C#) nebo řazené kolekce členů (Visual Basic).
Předchozí příklady jsou všechny funkčně ekvivalentní, ale existují mírné rozdíly v jejich použitelnosti a jejich podkladových implementacích.
Kompromisy
Možná budete chtít vždy používat ValueTuple přes Tuplea anonymní typy, ale měli byste zvážit kompromisy. Typy ValueTuple jsou proměnlivé, zatímco Tuple jsou jen pro čtení. Anonymní typy lze použít ve stromech výrazů, zatímco řazené kolekce členů nelze. Následující tabulka obsahuje přehled některých klíčových rozdílů.
Klíčové rozdíly
Název | Modifikátor přístupu | Typ | Název vlastního člena | Podpora dekonstrukce | Podpora stromu výrazů |
---|---|---|---|---|---|
Anonymní typy | internal |
class |
✔️ | ❌ | ✔️ |
Tuple | public |
class |
❌ | ❌ | ✔️ |
ValueTuple | public |
struct |
✔️ | ✔️ | ❌ |
Serializace
Jedním z důležitých aspektů při výběru typu, je to, zda bude nutné serializovat. Serializace je proces převodu stav objektu do tvaru, který může být zachována nebo přenosu. Další informace naleznete v tématu serializace. Pokud je serializace důležitá, vytvoření class
nebo struct
je upřednostňované před anonymními typy nebo typy řazené kolekce členů.
Výkon
Výkon mezi těmito typy závisí na scénáři. Hlavním dopadem je kompromis mezi přiděleními a kopírováním. Ve většině scénářů je dopad malý. Pokud by mohlo dojít k významným dopadům, měla by být přijata měření, aby bylo možné rozhodnutí informovat.
Závěr
Jako vývojář, který si vybírá mezi řazené kolekce členů a anonymními typy, je potřeba zvážit několik faktorů. Obecně řečeno, pokud nepracujete se stromy výrazů a máte rádi syntaxi řazené kolekce členů, zvolte ValueTuple , protože poskytují typ hodnoty s flexibilitou pro pojmenování vlastností. Pokud pracujete se stromy výrazů a chcete raději pojmenovat vlastnosti, zvolte anonymní typy. V opačném případě použijte Tuple.