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