Sdílet prostřednictvím


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

K vytvoření běžných hodnot kolekce použijte výraz kolekce . Výraz kolekce je terse syntaxe, kterou můžete přiřadit mnoha různým typům kolekcí. Výraz kolekce obsahuje posloupnost prvků mezi [ a ] hranatými závorkami.

Referenční dokumentace jazyka C# dokumentuje naposledy vydané verze jazyka C#. Obsahuje také počáteční dokumentaci k funkcím ve verzi Public Preview pro nadcházející jazykovou verzi.

Dokumentace identifikuje všechny funkce, které byly poprvé představeny v posledních třech verzích jazyka nebo v aktuálních verzích Public Preview.

Návod

Informace o tom, kdy byla funkce poprvé představena v jazyce C#, najdete v článku o historii verzí jazyka C#.

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 můžete 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 kompilace, například při inicializaci 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í hodnot kolekce ve výrazu kolekce použijte element rozprostř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 . Výraz 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 můžete převést na různé typy kolekcí, včetně:

Poznámka:

K inicializaci vložených polí nemůžete použít výrazy kolekce. Vložená pole vyžadují jinou syntaxi inicializace.

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:

  • Lepší převod prvků je vhodnější než lepší převod typu kolekce. Jinými slovy, typ prvků ve výrazu kolekce má větší důležitost než typ kolekce. Tato pravidla jsou popsána ve specifikaci funkce pro lepší převod z výrazu kolekce.
  • 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 SpanReadOnlySpan, bezpečný kontext objektu span pochází 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 Lengthv počítané kolekci vytvoří stejnou hodnotu jako počet prvků při vytváření výčtu.
  • Typy v System.Collections.Generic oboru názvů jsou zdarma s vedlejším účinkem. Kompilátor může optimalizovat scénáře, ve kterých se tyto typy můžou používat jako zprostředkující hodnoty, ale jinak je nezpřístupňuje.
  • Volání příslušného .AddRange(x) člena kolekce má za následek stejnou konečnou hodnotu jako iterace x a přidání všech jeho výčtových hodnot jednotlivě do kolekce pomocí .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í není definováno při použití daného typu kolekce s výrazy kolekce.

Vaše typy se přihlašují k podpoře výrazů kolekce napsáním Create() metody a použitím System.Runtime.CompilerServices.CollectionBuilderAttribute atributu u typu kolekce pro 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;
    private readonly int _count;

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

    public int Count => _count;
    
    public char this[int index]
    {
        get
        {
            if (index >= _count)
                throw new IndexOutOfRangeException();
            return _buffer[index];
        }
    }

    public IEnumerator<char> GetEnumerator()
    {
        for (int i = 0; i < _count; i++)
        {
            yield return _buffer[i];
        }
    }
    
    IEnumerator IEnumerable.GetEnumerator() => 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 konečný parametr typu ReadOnlySpan<char>. Parametr ReadOnlySpan typu musí odpovídat typu prvku kolekce. Metoda tvůrce, která vrací obecnou kolekci, má obecný ReadOnlySpan<T> jako jeho parametr. Metoda musí být přístupná a static.

Počínaje jazykem Create C# 15 může mít metoda před parametrem ReadOnlySpan<T> další parametry. Hodnoty do těchto parametrů můžete předat pomocí with(...) elementu ve výrazu kolekce. Podrobnosti najdete v argumentech Tvůrce kolekcí .

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.

Argumenty výrazů kolekce

Počínaje jazykem C# 15 můžete předat argumenty konstruktoru podkladové kolekce nebo metodě továrny pomocí with(...) elementu jako prvního prvku ve výrazu kolekce. Tato funkce umožňuje zadat kapacitu, porovnávače nebo jiné parametry konstruktoru přímo v syntaxi výrazu kolekce. Další informace najdete ve specifikaci funkce argumentů výrazů kolekce.

Prvek with(...) musí být prvním prvkem ve výrazu kolekce. Argumenty deklarované v elementu with(...) jsou předány příslušnému konstruktoru nebo vytvořit metodu na základě cílového typu. Pro argumenty v elementu with můžete použít libovolný platný výraz.

Argumenty konstruktoru

Pokud cílový typ je třída nebo struktura, která implementuje System.Collections.IEnumerable, argumenty jsou with(...) vyhodnoceny a výsledky jsou předány konstruktoru. Kompilátor používá překlad přetížení k výběru nejvhodnějšího konstruktoru:

public void CollectionArgumentsExamples()
{
    string[] values = ["one", "two", "three"];

    // Pass capacity argument to List<T> constructor
    List<string> names = [with(capacity: values.Length * 2), .. values];

    // Pass comparer argument to HashSet<T> constructor
    HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];
    // set contains only one element because all strings are equal with OrdinalIgnoreCase

    // Pass capacity to IList<T> (uses List<T> constructor)
    IList<int> numbers = [with(capacity: 100), 1, 2, 3];
}

V předchozím příkladu:

Argumenty tvůrce kolekcí

Pro typy s argumenty System.Runtime.CompilerServices.CollectionBuilderAttributedeklarované v elementu with(...) jsou vyhodnoceny a výsledky jsou předány metodě create před parametr.ReadOnlySpan<T> Tato funkce umožňuje vytvářet metody pro příjem parametrů konfigurace:

internal static class MySetBuilder
{
    internal static MySet<T> Create<T>(ReadOnlySpan<T> items) => new MySet<T>(items);
    internal static MySet<T> Create<T>(IEqualityComparer<T> comparer, ReadOnlySpan<T> items) => 
        new MySet<T>(items, comparer);
}

Pak můžete element použít with(...) k předání porovnávače:

public void CollectionBuilderArgumentsExample()
{
    // Pass comparer to a type with CollectionBuilder attribute
    // The comparer argument is passed before the ReadOnlySpan<T> parameter
    MySet<string> mySet = [with(StringComparer.OrdinalIgnoreCase), "A", "a", "B"];
    // mySet contains only two elements: "A" and "B"
}

Metoda create je vybrána pomocí rozlišení přetížení na základě zadaných argumentů. Obsahující ReadOnlySpan<T> prvky kolekce jsou vždy posledním parametrem.

Cílové typy rozhraní

Několik cílových typů rozhraní podporuje argumenty výrazů kolekce. Následující tabulka uvádí podporovaná rozhraní a jejich platné podpisy konstruktoru:

Rozhraní Podporované with prvky
IEnumerable<T>, IReadOnlyCollection<T>IReadOnlyList<T> () (pouze prázdné)
ICollection<T>, IList<T> (), (int capacity)

Pro IList<T> a ICollection<T>, kompilátor používá se System.Collections.Generic.List<T> zadaný konstruktor.

Restrictions

Element with(...) má následující omezení:

  • Musí to být první prvek ve výrazu kolekce.
  • Argumenty nemohou mít dynamic typ.
  • Nepodporuje se u polí nebo typů rozsahů (Span<T>, ReadOnlySpan<T>).