Volba mezi anonymními a tuply

Volba vhodného typu zahrnuje zvážení použitelnosti, výkonu a kompromisů v porovnání s jinými typy. Od verze C# 3.0 byly k dispozici anonymní typy, zatímco obecné typy System.Tuple<T1,T2> byly zavedeny s rozhraním .NET Framework 4.0. Od té doby byly zavedeny nové možnosti s podporou na úrovni jazyka, například System.ValueTuple<T1,T2>. Jak názvy naznačují, tyto možnosti 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 Language-Integrated Query (LINQ). 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í. Zvažte následující příklad, který inicializuje pole objektů DateTime a prochází je, přičemž je převádí 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 instancují pomocí operátoru new a z deklarace se odvozují názvy vlastností a jejich typy. 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á funkcionalita existuje s n-ticemi při projektování do dotazů LINQ, můžete vybrat vlastnosti do n-tic. Tyto n-tice procházejí dotazem stejně jako anonymní typy. Nyní zvažte následující příklad s použitím 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> instance zveřejňuje vlastnosti číslovaných položek, 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 System.Tuple typy referenčními class typy. Jedná se System.ValueTuple<T1,T2> však o typ hodnoty struct . Následující fragment kódu jazyka C# používá ValueTuple<string, long> k projekci do. Přiřazuje hodnotu použitím 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 n-ticích najdete v tématu Typy n-tic (referenční dokumentace jazyka C#) nebo N-tice (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 n-tice nelze. Následující tabulka obsahuje přehled některých klíčových rozdílů.

Hlavní 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, zda bude nutné, aby byl serializován. Serializace je proces převodu stavu objektu na formulář, který lze zachovat nebo přenést. Další informace naleznete v tématu serializace. Pokud je serializace důležitá, je vytvoření class nebo struct upřednostňováno před anonymními typy nebo typy n-tic.

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í k informovanému rozhodnutí.

Závěr

Jako vývojář, který si vybírá mezi n-ticemi a anonymními typy, existuje několik faktorů k úvaze. Obecně řečeno, pokud nepracujete se stromy výrazů a jste spokojeni se syntaxí n-tic, 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.

Viz také