Kolekce
Modul runtime .NET poskytuje mnoho typů kolekcí, které ukládají a spravují skupiny souvisejících objektů. Některé typy kolekcí, například System.Array, System.Span<T>a System.Memory<T> jsou rozpoznány v jazyce C#. Kromě toho rozhraní, jako System.Collections.Generic.IEnumerable<T> jsou rozpoznány v jazyce pro výčet prvků kolekce.
Kolekce poskytují flexibilní způsob práce se skupinami objektů. Různé kolekce můžete klasifikovat podle těchto charakteristik:
- Přístup k prvkům: Každá kolekce je možné vytvořit výčet pro přístup ke každému prvku v pořadí. Některé kolekce přistupují k prvkům pomocí indexu, pozice elementu v seřazené kolekci. Nejběžnějším příkladem je System.Collections.Generic.List<T>. Jiné kolekce přistupují k prvkům podle klíče, kde je hodnota přidružená k jednomu klíči. Nejběžnějším příkladem je System.Collections.Generic.Dictionary<TKey,TValue>. Můžete si vybrat mezi těmito typy kolekcí na základě toho, jak vaše aplikace přistupuje k prvkům.
- Profil výkonu: Každá kolekce má různé profily výkonu pro akce, jako je přidání prvku, vyhledání elementu nebo odebrání elementu. Typ kolekce můžete vybrat na základě operací používaných nejvíce ve vaší aplikaci.
- Dynamické zvětšování a zmenšování: Většina kolekcí podporuje dynamické přidávání nebo odebírání prvků. Zejména , ArraySystem.Span<T>, a System.Memory<T> ne.
Kromě těchto vlastností modul runtime poskytuje specializované kolekce, které brání přidávání nebo odebírání prvků nebo úpravám prvků kolekce. Další specializované kolekce poskytují bezpečnost souběžného přístupu v aplikacích s více vlákny.
Všechny typy kolekcí najdete v referenčních informacích k rozhraní .NET API. Další informace naleznete v tématu Běžně používané typy kolekcí a výběr třídy kolekce.
Poznámka:
V příkladech v tomto článku možná budete muset přidat direktivy using pro obory System.Collections.Generic
názvů a System.Linq
obory názvů.
Pole jsou reprezentována System.Array a mají podporu syntaxe v jazyce C#. Tato syntaxe poskytuje stručnější deklarace proměnných pole.
System.Span<T>ref struct
je typ, který poskytuje snímek přes sekvenci prvků bez kopírování těchto prvků. Kompilátor vynucuje pravidla zabezpečení, aby se zajistilo Span
, že nebude možné získat přístup po posloupnosti, na které odkazuje, už není v oboru. Používá se v mnoha rozhraních .NET API ke zlepšení výkonu. Memory<T> poskytuje podobné chování, když nemůžete použít ref struct
typ.
Počínaje jazykem C# 12 je možné inicializovat všechny typy kolekcí pomocí výrazu Collection.
Indexovatelné kolekce
Indexovatelná kolekce je jedna, kde můžete přistupovat ke každému prvku pomocí jeho indexu. Jeho index je počet prvků před ním v posloupnosti. Proto je odkaz na prvek podle indexu 0
prvním prvkem, index 1
je druhý atd. Tyto příklady používají List<T> třídu. Jedná se o nejběžnější indexovatelnou kolekci.
Následující příklad vytvoří a inicializuje seznam řetězců, odebere prvek a přidá prvek na konec seznamu. Po každé úpravě iteruje řetězce pomocí příkazu foreach nebo smyčky for
:
// 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
Následující příklad odebere prvky ze seznamu podle indexu. foreach
Místo příkazu používá for
příkaz, který iteruje sestupně. Metoda RemoveAt způsobí, že prvky po odebrání elementu mají nižší hodnotu indexu.
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
Pro typ prvků v sadě List<T>můžete také definovat vlastní třídu. V následujícím příkladu Galaxy
je třída, kterou používá, List<T> definována v kódu.
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; }
}
Kolekce párů klíč/hodnota
Tyto příklady používají Dictionary<TKey,TValue> třídu. Jedná se o nejběžnější kolekci slovníků. Slovníková kolekce umožňuje přístup k prvkům v kolekci pomocí klíče každého prvku. Každý doplněk slovníku se skládá z hodnoty a jeho přidruženého klíče.
Následující příklad vytvoří Dictionary
kolekci a iteruje prostřednictvím slovníku foreach
pomocí příkazu.
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}}
};
Následující příklad používá metodu ContainsKey Item[] a vlastnost Dictionary
k rychlému vyhledání položky podle klíče. Tato Item
vlastnost umožňuje přístup k položce v elements
kolekci pomocí jazyka elements[symbol]
C#.
if (elements.ContainsKey(symbol) == false)
{
Console.WriteLine(symbol + " not found");
}
else
{
Element theElement = elements[symbol];
Console.WriteLine("found: " + theElement.Name);
}
Následující příklad místo toho používá metodu TryGetValue k rychlému vyhledání položky podle klíče.
if (elements.TryGetValue(symbol, out Element? theElement) == false)
Console.WriteLine(symbol + " not found");
else
Console.WriteLine("found: " + theElement.Name);
Iterátory
Iterátor slouží k provedení vlastní iterace v kolekci. Iterátorem může být metoda nebo get
příslušenství. Iterátor používá příkaz yield return k vrácení každého prvku kolekce po jednom.
Iterátor můžete volat pomocí příkazu foreach . Každá iterace smyčky foreach
volá iterátor. yield return
Při dosažení příkazu v iterátoru se vrátí výraz a aktuální umístění v kódu se zachová. Spuštění se restartuje z daného umístění při příštím volání iterátoru.
Další informace najdete v tématu Iterátory (C#).
Následující příklad používá metodu iterátoru. Metoda iterátoru yield return
má příkaz, který je uvnitř smyčky for
. ListEvenNumbers
V metodě každá iterace foreach
těla příkazu vytvoří volání metody iterátoru, která pokračuje k dalšímu yield return
příkazu.
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 a kolekce
Jazykově integrovaný dotaz (LINQ) se dá použít pro přístup k kolekcím. Dotazy LINQ poskytují možnosti filtrování, řazení a seskupování. Další informace naleznete v tématu Začínáme s LINQ v jazyce C#.
Následující příklad spustí dotaz LINQ na obecný List
. Dotaz LINQ vrátí jinou kolekci, která obsahuje výsledky.
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}}
};