Sdílet prostřednictvím


Výrazy kolekce – referenční dokumentace jazyka C#

Výraz kolekce můžete použít k vytvoření běžných hodnot kolekce. Výraz kolekce je terse syntaxe, která se při vyhodnocování dá přiřadit mnoha různým typům kolekcí. Výraz kolekce obsahuje posloupnost prvků mezi [ a ] hranatými závorkami. Následující příklad deklaruje System.Span<T> prvek string a inicializuje je na dny v týdnu:

Span<string> weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
foreach (var day in weekDays)
{
    Console.WriteLine(day);
}

Výraz kolekce lze převést na mnoho různých typů kolekcí. První příklad ukazuje, jak inicializovat proměnnou pomocí výrazu kolekce. Následující kód ukazuje mnoho dalších umístění, kde můžete použít výraz kolekce:

// Initialize private field:
private static readonly ImmutableArray<string> _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

// property with expression body:
public IEnumerable<int> MaxDays =>
    [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

public int Sum(IEnumerable<int> values) =>
    values.Sum();

public void Example()
{
    // As a parameter:
    int sum = Sum([1, 2, 3, 4, 5]);
}

Výraz kolekce nelze použít, pokud se očekává konstanta kompilačního času, například inicializace konstanty nebo jako výchozí hodnota argumentu metody.

Oba předchozí příklady používaly konstanty jako prvky výrazu kolekce. Pro prvky můžete také použít proměnné, jak je znázorněno v následujícím příkladu:

string hydrogen = "H";
string helium = "He";
string lithium = "Li";
string beryllium = "Be";
string boron = "B";
string carbon = "C";
string nitrogen = "N";
string oxygen = "O";
string fluorine = "F";
string neon = "Ne";
string[] elements = [hydrogen, helium, lithium, beryllium, boron, carbon, nitrogen, oxygen, fluorine, neon];
foreach (var element in elements)
{
    Console.WriteLine(element);
}

Element Spread

K vloženým hodnotám kolekce ve výrazu kolekce použijete prvek šíření... Následující příklad vytvoří kolekci pro celou abecedu kombinací kolekce samohlásek, kolekce souhlásek a písmene "y", což může být:

string[] vowels = ["a", "e", "i", "o", "u"];
string[] consonants = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
                       "n", "p", "q", "r", "s", "t", "v", "w", "x", "z"];
string[] alphabet = [.. vowels, .. consonants, "y"];

Rozprostřený prvek ..vowelspři vyhodnocení vytvoří pět prvků: "a", "e", "i", "o"a "u". Rozprostřený prvek ..consonants vytvoří 20 prvků, číslo v matici consonants . Proměnná v elementu spread musí být výčet pomocí foreach příkazu. Jak je znázorněno v předchozím příkladu, můžete kombinovat rozprostřené prvky s jednotlivými prvky ve výrazu kolekce.

Převody

Výraz kolekce lze převést na různé typy kolekcí, včetně:

Důležité

Výraz kolekce vždy vytvoří kolekci, která obsahuje všechny prvky ve výrazu kolekce bez ohledu na cílový typ převodu. Pokud je System.Collections.Generic.IEnumerable<T>například cílem převodu , vygenerovaný kód vyhodnotí výraz kolekce a uloží výsledky v kolekci v paměti.

Toto chování se liší od LINQ, kdy se sekvence nemusí vytvořit instance, dokud se nevypíše. Výrazy kolekce nemůžete použít k vygenerování nekonečné sekvence, která se nevyčtou.

Kompilátor používá statickou analýzu k určení nejvýkonnějšího způsobu vytvoření kolekce deklarované pomocí výrazu kolekce. Například prázdný výraz kolekce , lze zjistit, []jako Array.Empty<T>() by cíl nebyl změněn po inicializaci. Pokud je System.Span<T> cílem nebo System.ReadOnlySpan<T>, úložiště může být přiděleno zásobníku. Specifikace funkce výrazů kolekce určuje pravidla, která musí kompilátor dodržovat.

Mnoho rozhraní API je přetížené více typy kolekcí jako parametry. Vzhledem k tomu, že výraz kolekce lze převést na mnoho různých typů výrazů, mohou tato rozhraní API vyžadovat přetypování výrazu kolekce k určení správného převodu. Některá z nejednoznačností řeší následující pravidla převodu:

  • Převod na Span<T>, ReadOnlySpan<T>nebo jiný ref struct typ je lepší než převod na typ struktury, který není odkaz.
  • Převod na typ neinterface je lepší než převod na typ rozhraní.

Při převodu výrazu kolekce na nebo Span ReadOnlySpanse bezpečný kontext objektu span přebírá z bezpečného kontextu všech prvků zahrnutých v rozsahu. Podrobná pravidla najdete ve specifikaci výrazu kolekce.

Tvůrce kolekcí

Výrazy kolekce fungují s libovolným typem kolekce, který se dobře chová. Dobře chovaná kolekce má následující vlastnosti:

  • Hodnota Count nebo Length v počítané kolekci vytvoří stejnou hodnotu jako počet prvků při vytváření výčtu.
  • U typů v System.Collections.Generic oboru názvů se předpokládá, že jsou bez vedlejšího efektu. Kompilátor může například optimalizovat scénáře, ve kterých se takové typy můžou používat jako zprostředkující hodnoty, ale jinak nebudou vystaveny.
  • Volání některého příslušného .AddRange(x) člena kolekce bude mít za následek stejnou konečnou hodnotu jako iterace x a přidání všech jeho výčtových hodnot jednotlivě do kolekce s .Add.

Všechny typy kolekcí v modulu runtime .NET se dobře chovají.

Upozorňující

Pokud se vlastní typ kolekce dobře nechová, chování při použití daného typu kolekce s výrazy kolekce není definováno.

Vaše typy se přihlašují k podpoře výrazů kolekce tím, že zapíší metodu Create() a použijí typ System.Runtime.CompilerServices.CollectionBuilderAttribute kolekce k označení metody tvůrce. Představte si například aplikaci, která používá vyrovnávací paměti s pevnou délkou 80 znaků. Tato třída může vypadat nějak takto:

public class LineBuffer : IEnumerable<char>
{
    private readonly char[] _buffer = new char[80];

    public LineBuffer(ReadOnlySpan<char> buffer)
    {
        int number = (_buffer.Length < buffer.Length) ? _buffer.Length : buffer.Length;
        for (int i = 0; i < number; i++)
        {
            _buffer[i] = buffer[i];
        }
    }

    public IEnumerator<char> GetEnumerator() => _buffer.AsEnumerable<char>().GetEnumerator();
    IEnumerator IEnumerable.GetEnumerator() => _buffer.GetEnumerator();

    // etc
}

Chcete ho použít s výrazy kolekce, jak je znázorněno v následující ukázce:

LineBuffer line = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'];

Typ LineBuffer implementuje IEnumerable<char>, takže kompilátor ho rozpozná jako kolekci char položek. Parametr typu implementovaného System.Collections.Generic.IEnumerable<T> rozhraní označuje typ prvku. Abyste mohli přiřadit výrazy kolekce k objektu LineBuffer , musíte do své aplikace vytvořit dvě dodatky. Nejprve musíte vytvořit třídu, která obsahuje metodu Create :

internal static class LineBufferBuilder
{
    internal static LineBuffer Create(ReadOnlySpan<char> values) => new LineBuffer(values);
}

Metoda Create musí vrátit LineBuffer objekt a musí mít jeden parametr typu ReadOnlySpan<char>. Parametr ReadOnlySpan typu musí odpovídat typu prvku kolekce. Metoda tvůrce, která vrací obecnou kolekci, by měla obecný ReadOnlySpan<T> jako jeho parametr. Metoda musí být přístupná a static.

Nakonec musíte přidat CollectionBuilderAttribute deklaraci LineBuffer třídy:

[CollectionBuilder(typeof(LineBufferBuilder), "Create")]

První parametr poskytuje název třídy Builderu. Druhý atribut poskytuje název metody tvůrce.