Share via


Verzamelingen

De .NET-runtime biedt veel verzamelingstypen waarmee groepen gerelateerde objecten worden opgeslagen en beheerd. Sommige verzamelingstypen, zoals System.Array, System.Span<T>en System.Memory<T> worden herkend in de C#-taal. Bovendien worden interfaces zoals System.Collections.Generic.IEnumerable<T> herkend in de taal voor het inventariseren van de elementen van een verzameling.

Verzamelingen bieden een flexibele manier om te werken met groepen objecten. U kunt verschillende verzamelingen classificeren op basis van deze kenmerken:

  • Toegang tot elementen: elke verzameling kan worden geïnventariseerd voor toegang tot elk element in de volgorde. Sommige verzamelingen hebben toegang tot elementen per index, de positie van het element in een geordende verzameling. Het meest voorkomende voorbeeld is System.Collections.Generic.List<T>. Andere verzamelingen hebben toegang tot elementen per sleutel, waarbij een waarde aan één sleutel is gekoppeld. Het meest voorkomende voorbeeld is System.Collections.Generic.Dictionary<TKey,TValue>. U kiest tussen deze verzamelingstypen op basis van hoe uw app toegang heeft tot elementen.
  • Prestatieprofiel: elke verzameling heeft verschillende prestatieprofielen voor acties zoals het toevoegen van een element, het zoeken naar een element of het verwijderen van een element. U kunt een verzamelingstype kiezen op basis van de bewerkingen die het meest in uw app worden gebruikt.
  • Dynamisch vergroten en verkleinen: de meeste verzamelingen ondersteunen het dynamisch toevoegen of verwijderen van elementen. Met name, Arrayen System.Span<T>System.Memory<T> niet.

Naast deze kenmerken biedt de runtime gespecialiseerde verzamelingen die voorkomen dat elementen worden toegevoegd of verwijderd of de elementen van de verzameling worden gewijzigd. Andere gespecialiseerde verzamelingen bieden veiligheid voor gelijktijdige toegang in apps met meerdere threads.

U vindt alle verzamelingstypen in de .NET API-verwijzing. Zie Veelgebruikte verzamelingstypen en een verzamelingsklasse selecteren voor meer informatie.

Notitie

Voor de voorbeelden in dit artikel moet u mogelijk instructies toevoegen voor de System.Collections.Generic en System.Linq naamruimten.

Matrices worden vertegenwoordigd door System.Array en hebben syntaxisondersteuning in de C#-taal. Deze syntaxis biedt beknoptere declaraties voor matrixvariabelen.

System.Span<T> is een ref struct type dat een momentopname biedt over een reeks elementen zonder deze elementen te kopiëren. De compiler dwingt veiligheidsregels af om ervoor te zorgen dat de Span sequentie niet meer toegankelijk is nadat de sequentie waarnaar wordt verwezen, niet meer binnen het bereik valt. Het wordt gebruikt in veel .NET-API's om de prestaties te verbeteren. Memory<T> biedt vergelijkbaar gedrag wanneer u geen ref struct type kunt gebruiken.

Vanaf C# 12 kunnen alle verzamelingstypen worden geïnitialiseerd met behulp van een verzamelingsexpressie.

Indexeerbare verzamelingen

Een indexeerbare verzameling is een verzameling waar u toegang hebt tot elk element met behulp van de index. De index is het aantal elementen voordat deze in de reeks wordt opgenomen. Daarom is de elementreferentie per index 0 het eerste element, de index 1 is de tweede, enzovoort. In deze voorbeelden wordt de List<T> klasse gebruikt. Dit is de meest voorkomende indexeerbare verzameling.

In het volgende voorbeeld wordt een lijst met tekenreeksen gemaakt en geïnitialiseerd, wordt een element verwijderd en wordt een element toegevoegd aan het einde van de lijst. Na elke wijziging doorloopt deze de tekenreeksen met behulp van een foreach-instructie of een for lus:

// Create a list of strings by using a
// collection initializer.
List<string> salmons = ["chinook", "coho", "pink", "sockeye"];

// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

// Remove an element from the list by specifying
// the object.
salmons.Remove("coho");


// Iterate using the index:
for (var index = 0; index < salmons.Count; index++)
{
    Console.Write(salmons[index] + " ");
}
// Output: chinook pink sockeye

// Add the removed element
salmons.Add("coho");
// Iterate through the list.
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook pink sockeye coho

In het volgende voorbeeld worden elementen uit een lijst per index verwijderd. In plaats van een foreach instructie wordt een for instructie gebruikt die in aflopende volgorde wordt herhaald. De RemoveAt methode zorgt ervoor dat elementen na een verwijderd element een lagere indexwaarde hebben.

List<int> numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

// Remove odd numbers.
for (var index = numbers.Count - 1; index >= 0; index--)
{
    if (numbers[index] % 2 == 1)
    {
        // Remove the element by specifying
        // the zero-based index in the list.
        numbers.RemoveAt(index);
    }
}

// Iterate through the list.
// A lambda expression is placed in the ForEach method
// of the List(T) object.
numbers.ForEach(
    number => Console.Write(number + " "));
// Output: 0 2 4 6 8

Voor het type elementen in de List<T>klasse kunt u ook uw eigen klasse definiëren. In het volgende voorbeeld wordt de Galaxy klasse die door de List<T> code wordt gebruikt, gedefinieerd in de code.

private static void IterateThroughList()
{
    var theGalaxies = new List<Galaxy>
    {
        new (){ Name="Tadpole", MegaLightYears=400},
        new (){ Name="Pinwheel", MegaLightYears=25},
        new (){ Name="Milky Way", MegaLightYears=0},
        new (){ Name="Andromeda", MegaLightYears=3}
    };

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears);
    }

    // Output:
    //  Tadpole  400
    //  Pinwheel  25
    //  Milky Way  0
    //  Andromeda  3
}

public class Galaxy
{
    public string Name { get; set; }
    public int MegaLightYears { get; set; }
}

Verzamelingen sleutel-waardepaar

In deze voorbeelden wordt de Dictionary<TKey,TValue> klasse gebruikt. Dit is de meest voorkomende woordenlijstverzameling. Met een woordenlijstverzameling kunt u toegang krijgen tot elementen in de verzameling met behulp van de sleutel van elk element. Elke toevoeging aan de woordenlijst bestaat uit een waarde en de bijbehorende sleutel.

In het volgende voorbeeld wordt een Dictionary verzameling gemaakt en wordt de woordenlijst herhaald met behulp van een foreach instructie.

private static void IterateThruDictionary()
{
    Dictionary<string, Element> elements = BuildDictionary();

    foreach (KeyValuePair<string, Element> kvp in elements)
    {
        Element theElement = kvp.Value;

        Console.WriteLine("key: " + kvp.Key);
        Console.WriteLine("values: " + theElement.Symbol + " " +
            theElement.Name + " " + theElement.AtomicNumber);
    }
}

public class Element
{
    public required string Symbol { get; init; }
    public required string Name { get; init; }
    public required int AtomicNumber { get; init; }
}

private static Dictionary<string, Element> BuildDictionary() =>
    new ()
    {
        {"K",
            new (){ Symbol="K", Name="Potassium", AtomicNumber=19}},
        {"Ca",
            new (){ Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        {"Sc",
            new (){ Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        {"Ti",
            new (){ Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };

In het volgende voorbeeld wordt de ContainsKey methode en de Item[] eigenschap gebruikt om Dictionary snel een item op sleutel te vinden. Item Met de eigenschap kunt u toegang krijgen tot een item in de elements verzameling met behulp van Celements[symbol]#.

if (elements.ContainsKey(symbol) == false)
{
    Console.WriteLine(symbol + " not found");
}
else
{
    Element theElement = elements[symbol];
    Console.WriteLine("found: " + theElement.Name);
}

In het volgende voorbeeld wordt de TryGetValue methode gebruikt om snel een item op sleutel te vinden.

if (elements.TryGetValue(symbol, out Element? theElement) == false)
    Console.WriteLine(symbol + " not found");
else
    Console.WriteLine("found: " + theElement.Name);

Iterators

Een iterator wordt gebruikt om een aangepaste iteratie uit te voeren voor een verzameling. Een iterator kan een methode of een get accessor zijn. Een iterator gebruikt een rendementsinstructie om elk element van de verzameling één voor één te retourneren.

U roept een iterator aan met behulp van een foreach-instructie . Elke iteratie van de foreach lus roept de iterator aan. Wanneer een yield return instructie wordt bereikt in de iterator, wordt er een expressie geretourneerd en blijft de huidige locatie in de code behouden. De uitvoering wordt opnieuw gestart vanaf die locatie wanneer de iterator de volgende keer wordt aangeroepen.

Zie Iterators (C#) voor meer informatie.

In het volgende voorbeeld wordt een iterator-methode gebruikt. De iterator-methode heeft een yield return instructie die zich in een for lus bevindt. In de ListEvenNumbers methode maakt elke iteratie van de hoofdtekst van de foreach instructie een aanroep naar de iterator-methode, die naar de volgende yield return instructie gaat.

private static void ListEvenNumbers()
{
    foreach (int number in EvenSequence(5, 18))
    {
        Console.Write(number.ToString() + " ");
    }
    Console.WriteLine();
    // Output: 6 8 10 12 14 16 18
}

private static IEnumerable<int> EvenSequence(
    int firstNumber, int lastNumber)
{
    // Yield even numbers in the range.
    for (var number = firstNumber; number <= lastNumber; number++)
    {
        if (number % 2 == 0)
        {
            yield return number;
        }
    }
}

LINQ en verzamelingen

LinQ (Language-Integrated Query) kan worden gebruikt voor toegang tot verzamelingen. LINQ-query's bieden mogelijkheden voor filteren, ordenen en groeperen. Zie Aan de slag met LINQ in C# voor meer informatie.

In het volgende voorbeeld wordt een LINQ-query uitgevoerd op een algemeen List. De LINQ-query retourneert een andere verzameling die de resultaten bevat.

private static void ShowLINQ()
{
    List<Element> elements = BuildList();

    // LINQ Query.
    var subset = from theElement in elements
                 where theElement.AtomicNumber < 22
                 orderby theElement.Name
                 select theElement;

    foreach (Element theElement in subset)
    {
        Console.WriteLine(theElement.Name + " " + theElement.AtomicNumber);
    }

    // Output:
    //  Calcium 20
    //  Potassium 19
    //  Scandium 21
}

private static List<Element> BuildList() => new()
    {
        { new(){ Symbol="K", Name="Potassium", AtomicNumber=19}},
        { new(){ Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        { new(){ Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        { new(){ Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };