Share via


Verzamelingsexpressies - C#-taalverwijzing

Gebruik een verzamelingsexpressie om algemene verzamelingswaarden te maken. Een verzamelingsexpressie is een terse-syntaxis die u kunt toewijzen aan veel verschillende verzamelingstypen. Een verzamelingsexpressie bevat een reeks elementen tussen [ haakjes ] .

De C#-taalreferentiedocumenten beschrijven de meest recent uitgebrachte versie van de C#-taal. Het bevat ook de eerste documentatie voor functies in openbare previews voor de aanstaande taalrelease.

De documentatie identificeert alle functies die voor het eerst zijn geïntroduceerd in de laatste drie versies van de taal of in de huidige openbare previews.

Aanbeveling

Raadpleeg het artikel over de versiegeschiedenis van de C#-taal om te achterhalen wanneer een functie voor het eerst is geïntroduceerd in C#.

In het volgende voorbeeld worden elementen System.Span<T>string declareren en geïnitialiseerd tot de dagen van de week:

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

U kunt een verzamelingsexpressie converteren naar veel verschillende verzamelingstypen. In het eerste voorbeeld werd gedemonstreerd hoe u een variabele initialiseert met behulp van een verzamelingsexpressie. De volgende code toont veel van de andere locaties waar u een verzamelingsexpressie kunt gebruiken:

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

U kunt geen verzamelingsexpressie gebruiken waarbij een compilatieconstante wordt verwacht, zoals bij het initialiseren van een constante of als de standaardwaarde voor een methodeargument.

In beide vorige voorbeelden zijn constanten gebruikt als de elementen van een verzamelingsexpressie. U kunt ook variabelen voor de elementen gebruiken, zoals wordt weergegeven in het volgende voorbeeld:

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

Verspreid element

Gebruik een verspreid element.. om inlineverzamelingswaarden in een verzamelingsexpressie te gebruiken. In het volgende voorbeeld wordt een verzameling voor het volledige alfabet gemaakt door een verzameling klinkers, een verzameling van de medeklinkers en de letter 'y' te combineren. Dit kan een van de volgende zijn:

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

Het verspreide element ..vowels, wanneer geëvalueerd, produceert vijf elementen: "a", "e", "i", "o"en "u". Het verspreide element ..consonants produceert 20 elementen, het getal in de consonants matrix. De expressie in een spread-element moet worden opgesomd met behulp van een foreach instructie. Zoals u in het vorige voorbeeld kunt zien, kunt u verspreide elementen combineren met afzonderlijke elementen in een verzamelingsexpressie.

Conversies

U kunt een verzamelingsexpressie converteren naar verschillende verzamelingstypen, waaronder:

Opmerking

U kunt verzamelingsexpressies niet gebruiken om inlinematrices te initialiseren. Voor inlinematrices zijn verschillende initialisatiesyntaxis vereist.

Belangrijk

Een verzamelingexpressie maakt altijd een verzameling die alle elementen in de verzamelingsexpressie bevat, ongeacht het doeltype van de conversie. Wanneer het doel van de conversie bijvoorbeeld is System.Collections.Generic.IEnumerable<T>, evalueert de gegenereerde code de verzamelingsexpressie en slaat de resultaten op in een in-memory verzameling.

Dit gedrag verschilt van LINQ, waarbij een reeks mogelijk pas wordt geïnstantieerd nadat deze is geïnventariseerd. U kunt geen verzamelingsexpressies gebruiken om een oneindige reeks te genereren die niet wordt geïnventariseerd.

De compiler maakt gebruik van statische analyse om de meest presterende manier te bepalen om de verzameling te maken die is gedeclareerd met een verzamelingsexpressie. De lege verzamelingsexpressie, []kan bijvoorbeeld worden gerealiseerd Array.Empty<T>() alsof het doel niet wordt gewijzigd na initialisatie. Wanneer het doel een System.Span<T> of System.ReadOnlySpan<T>is, kan de opslag worden gestapeld. In de functiespecificatie voor verzamelingsexpressies worden de regels opgegeven die de compiler moet volgen.

Veel API's zijn overbelast met meerdere verzamelingstypen als parameters. Omdat een verzamelingsexpressie kan worden geconverteerd naar veel verschillende expressietypen, vereisen deze API's mogelijk casts op de verzamelingsexpressie om de juiste conversie op te geven. Met de volgende conversieregels worden enkele dubbelzinnigheden opgelost:

  • Een betere elementconversie heeft de voorkeur boven een betere conversie van verzamelingstypen. Met andere woorden, het type elementen in de verzamelingsexpressie heeft meer belang dan het type verzameling. Deze regels worden beschreven in de functiespecificatie voor een betere conversie van verzamelingsexpressie.
  • Conversie naar Span<T>, ReadOnlySpan<T>of een ander ref struct type is beter dan een conversie naar een niet-refstructtype.
  • Conversie naar een niet-interfacetype is beter dan een conversie naar een interfacetype.

Wanneer u een verzamelingsexpressie converteert naar een Span of ReadOnlySpan, is de veilige context van het spanobject afkomstig van de veilige context van alle elementen die in de periode zijn opgenomen. Zie de specificatie van de verzamelingsexpressie voor gedetailleerde regels.

Opbouwfunctie voor verzamelingen

Verzamelingsexpressies werken met elk verzamelingstype dat goed werkt. Een goed gedragen verzameling heeft de volgende kenmerken:

  • De waarde van Count of Length op een aftelbare verzameling produceert dezelfde waarde als het aantal elementen dat wordt opgesomd.
  • De typen in de System.Collections.Generic naamruimte worden geacht neveneffectvrij te zijn. Als zodanig kan de compiler scenario's optimaliseren waarbij dergelijke typen kunnen worden gebruikt als intermediaire waarden, maar anders niet beschikbaar worden gesteld.
  • Een aanroep van een van toepassing zijnde .AddRange(x) leden in een verzameling resulteert in dezelfde uiteindelijke waarde als het herhalen x en toevoegen van alle geïnventareerde waarden afzonderlijk aan de verzameling met .Add.

Alle verzamelingstypen in de .NET-runtime werken goed.

Waarschuwing

Als een aangepast verzamelingstype niet goed werkt, is het gedrag niet gedefinieerd wanneer u dat verzamelingstype gebruikt met verzamelingsexpressies.

Uw typen kiezen voor ondersteuning voor verzamelingsexpressies door een Create() methode te schrijven en het System.Runtime.CompilerServices.CollectionBuilderAttribute op het verzamelingstype toe te passen om de opbouwmethode aan te geven. Denk bijvoorbeeld aan een toepassing die gebruikmaakt van buffers met vaste lengte van 80 tekens. Deze klasse kan er ongeveer als volgt uitzien:

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
}

U wilt deze gebruiken met verzamelingexpressies, zoals wordt weergegeven in het volgende voorbeeld:

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

Het LineBuffer type implementeert IEnumerable<char>, zodat de compiler het herkent als een verzameling char items. De typeparameter van de geïmplementeerde System.Collections.Generic.IEnumerable<T> interface geeft het elementtype aan. U moet twee toevoegingen aan uw toepassing maken om verzamelingsexpressies toe te wijzen aan een LineBuffer object. Eerst moet u een klasse maken die een Create methode bevat:

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

De Create methode moet een LineBuffer object retourneren en moet één parameter van het type ReadOnlySpan<char>hebben. De typeparameter van de ReadOnlySpan verzameling moet overeenkomen met het elementtype van de verzameling. Een opbouwmethode die een algemene verzameling retourneert, heeft de algemene ReadOnlySpan<T> als parameter. De methode moet toegankelijk zijn en static.

Ten slotte moet u de declaratie van de CollectionBuilderAttributeLineBuffer klasse toevoegen:

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

De eerste parameter bevat de naam van de Builder-klasse . Het tweede kenmerk bevat de naam van de opbouwmethode.