Megosztás a következőn keresztül:


Gyűjteménykifejezések – C# nyelvi referencia

Gyűjteménykifejezéssel közös gyűjteményértékeket hozhat létre. A gyűjteménykifejezések olyan terse szintaxisok, amelyek kiértékelésekor számos különböző gyűjteménytípushoz rendelhetők. A gyűjteménykifejezések elemek sorozatát tartalmazzák a zárójelek és ] a zárójelek között[. Az alábbi példa egy elemeket System.Span<T>string deklarál, és inicializálja őket a hét napjaira:

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

A gyűjteménykifejezések számos különböző gyűjteménytípusra konvertálhatók. Az első példa bemutatja, hogyan inicializálhat egy változót gyűjteménykifejezéssel. Az alábbi kód számos más helyet mutat be, ahol gyűjteménykifejezést használhat:

// 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]);
}

Nem használhat olyan gyűjteménykifejezést, amelyben fordítási időállandót várnak, például inicializálhat egy állandót, vagy egy metódusargumentum alapértelmezett értékeként.

Mindkét előző példa konstansokat használt egy gyűjteménykifejezés elemeiként. Az elemekhez változókat is használhat az alábbi példában látható módon:

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);
}

Oldalpár elem

A gyűjteménykifejezések beágyazott gyűjteményértékeivel egy oldalpár elemet.. használ. Az alábbi példa létrehoz egy gyűjteményt a teljes ábécé számára a magánhangzók gyűjteményének, a mássalhangzók gyűjteményének és az "y" betűnek a kombinálásával, amely a következő lehet:

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"];

Az oldalpárelem ..vowelskiértékelésekor öt elemet hoz létre: "a", "e", "i", "o"és "u". Az oldalpár ..consonants 20 elemet állít elő, a tömbben lévő consonants számot. Az eloszláselem változójának számba kell vennie egy foreach utasítással. Ahogy az előző példában is látható, az oldalpár elemeit egyesítheti a gyűjteménykifejezések egyes elemeivel.

Konverziók

A gyűjteménykifejezések különböző gyűjteménytípusokká konvertálhatók, például:

Fontos

A gyűjteménykifejezések mindig létrehoznak egy gyűjteményt, amely a gyűjteménykifejezés összes elemét tartalmazza, függetlenül az átalakítás céltípusától. Ha például az átalakítás System.Collections.Generic.IEnumerable<T>célja, a generált kód kiértékeli a gyűjteménykifejezést, és egy memórián belüli gyűjteményben tárolja az eredményeket.

Ez a viselkedés különbözik a LINQ-tól, ahol előfordulhat, hogy a sorozat nem lesz példányosítva, amíg meg nem történik a számbavétele. Gyűjteménykifejezésekkel nem hozhat létre olyan végtelen sorozatot, amely nem lesz számba vehető.

A fordító statikus elemzéssel határozza meg a gyűjtemény gyűjteménykifejezéssel deklarált létrehozásának leghatékonyabb módját. Az üres gyűjteménykifejezés például úgy valósítható meg, []mintha Array.Empty<T>() a cél nem módosul az inicializálás után. Ha a cél egy System.Span<T> vagy System.ReadOnlySpan<T>, a tárolót lehet lefoglalni. A gyűjteménykifejezések funkciós specifikációja meghatározza, hogy a fordítónak mely szabályokat kell követnie.

Számos API paraméterként több gyűjteménytípussal van túlterhelve. Mivel a gyűjteménykifejezések számos különböző kifejezéstípusra konvertálhatók, előfordulhat, hogy ezek az API-k megkövetelik a gyűjteménykifejezésen a megfelelő átalakítás megadását. Az alábbi konverziós szabályok feloldanak néhány kétértelműséget:

  • Span<T>Az átalakítás , ReadOnlySpan<T>vagy egy másik ref struct típus jobb, mint egy nem átstrukturálási típusra való átalakítás.
  • A nem betűs típusra való átalakítás jobb, mint egy felülettípusra való átalakítás.

Ha egy gyűjteménykifejezést átalakítanak Span egy vagy ReadOnlySpantöbbre, a span objektum biztonságos környezete a spanban található összes elem biztonságos környezetéből származik. Részletes szabályokért tekintse meg a Gyűjtemény kifejezés specifikációját.

Gyűjteményszerkesztő

A gyűjteménykifejezések bármilyen jól működő gyűjteménytípussal működnek. A jól viselkedő gyűjtemények jellemzői a következők:

  • Egy megszámlálható gyűjtemény értéke CountLength ugyanazt az értéket eredményezi, mint az elemek számának számbavétele.
  • A névtérben lévő System.Collections.Generic típusok vélelmezhetően mellékhatásmentesek. Így a fordító optimalizálhatja azokat a forgatókönyveket, amelyekben az ilyen típusok köztes értékekként használhatók, de máskülönben nem lesznek közzétéve.
  • A gyűjtemény néhány alkalmazható .AddRange(x) tagjának hívása ugyanazt a végső értéket eredményezi, mint az iterálás x , és az összes számba adott érték egyenként hozzáadva a gyűjteményhez .Add.

A .NET-futtatókörnyezet összes gyűjteménytípusa megfelelően működik.

Figyelmeztetés

Ha egy egyéni gyűjteménytípus nem megfelelően viselkedik, a gyűjteménytípus gyűjteménykifejezésekkel való használatakor a viselkedés nincs meghatározva.

A típusok egy Create() metódus megírásával és a System.Runtime.CompilerServices.CollectionBuilderAttribute gyűjtemény típusának alkalmazásával választják a gyűjteménykifejezések támogatását, hogy jelezzék a szerkesztőmetódust. Vegyük például egy olyan alkalmazást, amely rögzített hosszúságú puffereket használ 80 karakterből. Az osztály a következő kódhoz hasonlóan nézhet ki:

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
}

Az alábbi példában látható módon gyűjteménykifejezésekkel szeretné használni:

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

A LineBuffer típus implementálható IEnumerable<char>, így a fordító elemgyűjteményként char ismeri fel. A implementált System.Collections.Generic.IEnumerable<T> felület típusparamétere az elem típusát jelzi. Két kiegészítést kell hozzáadnia az alkalmazáshoz, hogy gyűjteménykifejezéseket rendelhessen egy LineBuffer objektumhoz. Először létre kell hoznia egy metódust tartalmazó osztályt Create :

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

A Create metódusnak egy objektumot LineBuffer kell visszaadnia, és egyetlen paramétert kell használnia.ReadOnlySpan<char> A típusparaméternek ReadOnlySpan meg kell egyeznie a gyűjtemény elemtípusával. Egy általános gyűjteményt visszaadó szerkesztőmetódus paramétere az általános ReadOnlySpan<T> . A metódusnak elérhetőnek kell lennie, és static.

Végül hozzá kell adnia a következőt az CollectionBuilderAttributeLineBuffer osztálydeklarációhoz:

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

Az első paraméter a Builder osztály nevét adja meg. A második attribútum a szerkesztő metódus nevét adja meg.