Dela via


Samlingar

.NET-körningen innehåller många samlingstyper som lagrar och hanterar grupper av relaterade objekt. Vissa av samlingstyperna, till exempel System.Array, System.Span<T>och System.Memory<T> identifieras på C#-språket. Dessutom identifieras gränssnitt som System.Collections.Generic.IEnumerable<T> på språket för att räkna upp elementen i en samling.

Samlingar är ett flexibelt sätt att arbeta med grupper av objekt. Du kan klassificera olika samlingar efter följande egenskaper:

  • Elementåtkomst: Varje samling kan räknas upp för att komma åt varje element i ordning. Vissa samlingar kommer åt element efter index, elementets position i en ordnad samling. Det vanligaste exemplet är System.Collections.Generic.List<T>. Andra samlingar får åtkomst till element efter nyckel, där ett värde är associerat med en enda nyckel. Det vanligaste exemplet är System.Collections.Generic.Dictionary<TKey,TValue>. Du väljer mellan de här samlingstyperna baserat på hur appen kommer åt element.
  • Prestandaprofil: Varje samling har olika prestandaprofiler för åtgärder som att lägga till ett element, hitta ett element eller ta bort ett element. Du kan välja en samlingstyp baserat på de åtgärder som används mest i din app.
  • Växa och krympa dynamiskt: De flesta samlingar har stöd för att lägga till eller ta bort element dynamiskt. ArrayFramför allt , System.Span<T>, och System.Memory<T> gör det inte.

Förutom dessa egenskaper tillhandahåller körningen specialiserade samlingar som förhindrar att element läggs till eller tas bort eller att elementen i samlingen ändras. Andra specialiserade samlingar ger säkerhet för samtidig åtkomst i appar med flera trådar.

Du hittar alla samlingstyper i .NET API-referensen. Mer information finns i Vanliga samlingstyper och Välja en samlingsklass.

Kommentar

För exemplen i den här artikeln kan du behöva lägga till med hjälp av direktiv för System.Collections.Generic namnrymderna och System.Linq .

Matriser representeras av System.Array och har syntaxstöd på C#-språket. Den här syntaxen ger mer koncisa deklarationer för matrisvariabler.

System.Span<T> är en ref struct typ som ger en ögonblicksbild över en sekvens med element utan att kopiera dessa element. Kompilatorn tillämpar säkerhetsregler för att säkerställa Span att den inte kan nås efter den sekvens som den refererar till inte längre finns i omfånget. Det används i många .NET-API:er för att förbättra prestanda. Memory<T> ger liknande beteende när du inte kan använda en ref struct typ.

Från och med C# 12 kan alla samlingstyper initieras med ett samlingsuttryck.

Indexerbara samlingar

En indexerbar samling är en samling där du kan komma åt varje element med hjälp av dess index. Dess index är antalet element före det i sekvensen. Därför är elementreferensen per index 0 det första elementet, indexet 1 är det andra och så vidare. I de här exemplen List<T> används klassen . Det är den vanligaste indexerbara samlingen.

I följande exempel skapas och initieras en lista med strängar, tar bort ett element och lägger till ett element i slutet av listan. Efter varje ändring itererar den genom strängarna med hjälp av en foreach-instruktion eller en for loop:

// 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

I följande exempel tar du bort element från en lista efter index. I stället för en foreach instruktion använder den en for -instruktion som itererar i fallande ordning. Metoden RemoveAt gör att element efter ett borttaget element har ett lägre indexvärde.

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

För typen av element i List<T>kan du också definiera din egen klass. I följande exempel definieras klassen Galaxy som används av List<T> koden.

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

Nyckel/värde-parsamlingar

I de här exemplen Dictionary<TKey,TValue> används klassen . Det är den vanligaste ordlistesamlingen. Med en ordlistesamling kan du komma åt element i samlingen med hjälp av nyckeln för varje element. Varje tillägg till ordlistan består av ett värde och dess associerade nyckel.

I följande exempel skapas en Dictionary samling och itereras via ordlistan med hjälp av en foreach -instruktion.

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

I följande exempel används ContainsKey metoden och Item[] egenskapen Dictionary för för att snabbt hitta ett objekt efter nyckel. Med Item egenskapen kan du komma åt ett objekt i elements samlingen med hjälp elements[symbol] av i C#.

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

I följande exempel används TryGetValue i stället metoden för att snabbt hitta ett objekt efter nyckel.

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

Iteratorer

En iterator används för att utföra en anpassad iteration över en samling. En iterator kan vara en metod eller en get accessor. En iterator använder en avkastningsreturinstruktur för att returnera varje element i samlingen en i taget.

Du anropar en iterator med hjälp av en foreach-instruktion . Varje iteration av loopen foreach anropar iteratorn. När en yield return -instruktion nås i iteratorn returneras ett uttryck och den aktuella platsen i koden behålls. Körningen startas om från den platsen nästa gång iteratorn anropas.

Mer information finns i Iteratorer (C#).

I följande exempel används en iteratormetod. Iteratormetoden har en yield return -instruktion som finns i en for loop. ListEvenNumbers I -metoden skapar varje iteration av instruktionstexten foreach ett anrop till iteratormetoden, som fortsätter till nästa yield return instruktion.

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 och samlingar

Språkintegrerad fråga (LINQ) kan användas för att komma åt samlingar. LINQ-frågor tillhandahåller filtrerings-, beställnings- och grupperingsfunktioner. Mer information finns i Komma igång med LINQ i C#.

I följande exempel körs en LINQ-fråga mot en allmän List. LINQ-frågan returnerar en annan samling som innehåller resultatet.

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