Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
Använd ett samlingsuttryck för att skapa gemensamma samlingsvärden. Ett samlingsuttryck är en terse-syntax som du kan tilldela till många olika samlingstyper. Ett samlingsuttryck innehåller en sekvens med element mellan [ och ] hakparenteser.
C#-språkreferensen dokumenterar den senaste versionen av C#-språket. Den innehåller även inledande dokumentation för funktioner i offentliga förhandsversioner för den kommande språkversionen.
Dokumentationen identifierar alla funktioner som först introducerades i de tre senaste versionerna av språket eller i aktuella offentliga förhandsversioner.
Tips/Råd
Information om när en funktion först introducerades i C# finns i artikeln om språkversionshistoriken för C#.
I följande exempel deklareras ett System.Span<T> element string och initieras till veckodagarna:
Span<string> weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
foreach (var day in weekDays)
{
Console.WriteLine(day);
}
Du kan konvertera ett samlingsuttryck till många olika samlingstyper. Det första exemplet visade hur du initierar en variabel med hjälp av ett samlingsuttryck. Följande kod visar många av de andra platserna där du kan använda ett samlingsuttryck:
// 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]);
}
Du kan inte använda ett samlingsuttryck där en kompileringskonstant förväntas, till exempel när en konstant initieras eller som standardvärde för ett metodargument.
Båda föregående exempel använde konstanter som element i ett samlingsuttryck. Du kan också använda variabler för elementen, som du ser i följande exempel:
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);
}
Spridningselement
Använd ett spridningselement.. till infogade samlingsvärden i ett samlingsuttryck. I följande exempel skapas en samling för det fullständiga alfabetet genom att kombinera en samling vokaler, en samling konsonanter och bokstaven "y", vilket kan vara antingen:
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"];
Spread-elementet ..vowels, när det utvärderas, producerar fem element: "a", "e", "i", "o"och "u". Spridningselementet ..consonants genererar 20 element, talet i matrisen consonants . Uttrycket i ett spridningselement måste kunna räknas upp med hjälp av en foreach -instruktion. Som du ser i föregående exempel kan du kombinera spridningselement med enskilda element i ett samlingsuttryck.
Omvandlingar
Du kan konvertera ett samlingsuttryck till olika samlingstyper, inklusive:
- System.Span<T> och System.ReadOnlySpan<T>.
-
Matriser, till exempel
int[]ellerstring[]. - Alla typer med en create-metod vars parametertyp är
ReadOnlySpan<T>där det finns en implicit konvertering från samlingsuttryckstypen tillT. - Alla typer som stöder en insamlingsinitierare, till exempel System.Collections.Generic.List<T>. Vanligtvis innebär det här kravet att typen stöder System.Collections.Generic.IEnumerable<T> och det finns en tillgänglig
Addmetod för att lägga till objekt i samlingen. Det måste finnas en implicit konvertering från typen av samlingsuttryckselement till samlingens elementtyp. För spridningselement måste det finnas en implicit konvertering från spridningselementets typ till samlingens elementtyp. - Något av följande gränssnitt:
Anmärkning
Du kan inte använda samlingsuttryck för att initiera infogade matriser. Infogade matriser kräver olika initieringssyntax.
Viktigt!
Ett samlingsuttryck skapar alltid en samling som innehåller alla element i samlingsuttrycket, oavsett måltypen för konverteringen. När målet för konverteringen till exempel är System.Collections.Generic.IEnumerable<T>utvärderar den genererade koden samlingsuttrycket och lagrar resultatet i en minnesintern samling.
Det här beteendet skiljer sig från LINQ, där en sekvens kanske inte instansieras förrän den räknas upp. Du kan inte använda samlingsuttryck för att generera en oändlig sekvens som inte räknas upp.
Kompilatorn använder statisk analys för att fastställa det mest högpresterande sättet att skapa samlingen som deklarerats med ett samlingsuttryck. Till exempel kan det tomma samlingsuttrycket , []realiseras som Array.Empty<T>() om målet inte ändras efter initieringen. När målet är en System.Span<T> eller System.ReadOnlySpan<T>kan lagringen vara stackallokerad. Funktionsspecifikationen för samlingsuttryck anger de regler som kompilatorn måste följa.
Många API:er överbelastas med flera samlingstyper som parametrar. Eftersom ett samlingsuttryck kan konverteras till många olika uttryckstyper kan dessa API:er kräva casts i samlingsuttrycket för att ange rätt konvertering. Följande konverteringsregler löser några av tvetydigheterna:
- En bättre elementkonvertering föredras framför en bättre konvertering av samlingstyp. Med andra ord har typen av element i samlingsuttrycket större betydelse än typen av samling. Dessa regler beskrivs i funktionsspecifikationen för bättre konvertering från samlingsuttryck.
- Konvertering till Span<T>, ReadOnlySpan<T>eller en annan
ref structtyp är bättre än en konvertering till en icke-referens-struct-typ. - Konvertering till en icke-gränssnittstyp är bättre än en konvertering till en gränssnittstyp.
När du konverterar ett samlingsuttryck till ett Span eller ReadOnlySpan, kommer span-objektets säkra kontext från den säkra kontexten för alla element som ingår i intervallet. Detaljerade regler finns i specifikationen för samlingsuttryck.
Samlingsbyggare
Samlingsuttryck fungerar med alla samlingstyper som är väluppfostrade. En väluppfostrad samling har följande egenskaper:
- Värdet för
CountellerLengthpå en räknad samling genererar samma värde som antalet element när de räknas upp. - Typerna System.Collections.Generic i namnområdet är sidoeffektfria. Kompilatorn kan optimera scenarier där dessa typer kan användas som mellanliggande värden, men de exponeras inte annars.
- Ett anrop till en tillämplig
.AddRange(x)medlem i en samling resulterar i samma slutliga värde som att iterera överxoch lägga till alla sina uppräknade värden individuellt i samlingen med hjälp.Addav .
Alla samlingstyper i .NET-körningen är väluppfostrade.
Varning
Om en anpassad samlingstyp inte är väluppfostrad är beteendet odefinierat när du använder den samlingstypen med samlingsuttryck.
Dina typer väljer stöd för samlingsuttryck genom att skriva en Create() metod och tillämpa System.Runtime.CompilerServices.CollectionBuilderAttribute attributet på samlingstypen för att ange metoden builder. Tänk dig till exempel ett program som använder buffertar med fast längd på 80 tecken. Klassen kan se ut ungefär så här:
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
}
Du vill använda den med samlingsuttryck som du ser i följande exempel:
LineBuffer line = ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'];
Typen LineBuffer implementerar IEnumerable<char>, så kompilatorn identifierar den som en samling char objekt. Typparametern för det implementerade System.Collections.Generic.IEnumerable<T> gränssnittet anger elementtypen. Du måste göra två tillägg i ditt program för att kunna tilldela samlingsuttryck till ett LineBuffer objekt. Först måste du skapa en klass som innehåller en Create metod:
internal static class LineBufferBuilder
{
internal static LineBuffer Create(ReadOnlySpan<char> values) => new LineBuffer(values);
}
Metoden Create måste returnera ett LineBuffer objekt och den måste ha en slutlig parameter av typen ReadOnlySpan<char>. Typparametern ReadOnlySpan för måste matcha elementtypen för samlingen. En builder-metod som returnerar en generisk samling har den generiska ReadOnlySpan<T> som sin parameter. Metoden måste vara tillgänglig och static.
Från och med C# 15 Create kan metoden ha ytterligare parametrar före parametern ReadOnlySpan<T> . Du kan skicka värden till dessa parametrar med hjälp av ett with(...) element i samlingsuttrycket. Mer information finns i Samlingsbyggarargument .
Slutligen måste du lägga till i CollectionBuilderAttribute klassdeklarationen LineBuffer :
[CollectionBuilder(typeof(LineBufferBuilder), "Create")]
Den första parametern innehåller namnet på klassen Builder . Det andra attributet innehåller namnet på builder-metoden.
Argument för samlingsuttryck
Från och med C# 15 kan du skicka argument till den underliggande samlingens konstruktor eller fabriksmetod genom att använda ett with(...) element som det första elementet i ett samlingsuttryck. Med den här funktionen kan du ange kapacitet, jämförelsetal eller andra konstruktorparametrar direkt i syntaxen för samlingsuttryck. Mer information finns i funktionsspecifikationen för samlingsuttrycksargument.
Elementet with(...) måste vara det första elementet i samlingsuttrycket. Argumenten som deklareras i elementet with(...) skickas till lämplig konstruktor eller skapa-metod baserat på måltypen. Du kan använda valfritt giltigt uttryck för argumenten i elementet with .
Konstruktorargument
När måltypen är en klass eller struct som implementerar utvärderas System.Collections.IEnumerableargumenten i with(...) och resultaten skickas till konstruktorn. Kompilatorn använder överbelastningsmatchning för att välja den bästa matchande konstruktorn:
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];
}
I föregående exempel:
- Konstruktorn
List<string>med encapacityparameter anropas medvalues.Length * 2. - Konstruktorn
HashSet<string>med en System.Collections.Generic.IEqualityComparer<T> parameter anropas medStringComparer.OrdinalIgnoreCase. - För gränssnittsmåltyper som System.Collections.Generic.IList<T>skapar kompilatorn en
List<T>med den angivna kapaciteten.
Argument för samlingsbyggare
För typer med en System.Runtime.CompilerServices.CollectionBuilderAttributeutvärderas argumenten som deklareras i elementet with(...) och resultaten skickas till metoden create före parametern ReadOnlySpan<T> . Med den här funktionen kan du skapa metoder för att acceptera konfigurationsparametrar:
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);
}
Du kan sedan använda elementet with(...) för att skicka jämförelsen:
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"
}
Metoden create väljs med hjälp av överbelastningsmatchning baserat på de argument som angetts. Den ReadOnlySpan<T> som innehåller samlingselementen är alltid den sista parametern.
Gränssnittsmåltyper
Flera gränssnittsmåltyper stöder argument för samlingsuttryck. I följande tabell visas de gränssnitt som stöds och deras tillämpliga konstruktorsignaturer:
| Gränssnitt | Element som stöds with |
|---|---|
| IEnumerable<T>, IReadOnlyCollection<T>IReadOnlyList<T> |
() (endast tom) |
| ICollection<T>, IList<T> |
(), (int capacity) |
För IList<T> och ICollection<T>använder kompilatorn en System.Collections.Generic.List<T> med den angivna konstruktorn.
Restrictions
Elementet with(...) har följande begränsningar:
- Det måste vara det första elementet i samlingsuttrycket.
- Argument kan inte ha
dynamictyp. - Det stöds inte för matriser eller intervalltyper (
Span<T>,ReadOnlySpan<T>).