Verzamelingsexpressies - C#-taalverwijzing

U kunt een verzamelingsexpressie gebruiken om algemene verzamelingswaarden te maken. Een verzamelingsexpressie is een terse-syntaxis die, wanneer deze wordt geëvalueerd, kan worden toegewezen aan veel verschillende verzamelingstypen. Een verzamelingsexpressie bevat een reeks elementen tussen [ haakjes ] . 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);
}

Een verzamelingsexpressie kan worden geconverteerd 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 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 gebruiken voor de elementen, 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

U gebruikt een spread-element .. om inline-verzamelingswaarden 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 variabele 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

Een verzamelingsexpressie kan worden geconverteerd naar verschillende verzamelingstypen, waaronder:

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:

  • 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 een verzamelingsexpressie wordt geconverteerd naar een Span ofReadOnlySpan, wordt de veilige context van het spanobject opgehaald uit de veilige context van alle elementen die in de spanwijdte 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 waarin 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 wanneer u dat verzamelingstype gebruikt met verzamelingsexpressies niet gedefinieerd.

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 = 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
}

U wilt deze gebruiken met verzamelingsexpressies, 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, zou de algemene ReadOnlySpan<T> als parameter hebben. 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.