.NET 运行时提供了许多集合类型,用于存储和管理相关对象的组。 某些集合类型(例如 System.Array, System.Span
集合提供灵活的方式来使用对象组。 可按以下特征对不同的集合进行分类:
元素访问:可以枚举每个集合以按顺序访问每个元素。 某些集合可通过索引(元素在有序集合中的位置)访问元素。 最常见的示例是 System.Collections.Generic.List
性能配置文件:每个集合都有不同的性能配置文件,可用于添加元素、查找元素或移除元素等操作。 可以根据应用中最常用的操作选取集合类型。
动态增长和收缩:大多数集合支持动态添加或移除元素。 需要注意的是,Array、System.Span
除了这些特征之外,运行时还提供专用集合,这些集合可阻止添加或移除元素,或修改集合的元素。 其他专用集合为多线程应用中的并发访问提供安全性。
可以在 .NET API 参考中找到所有集合类型。 有关其他信息,请参阅常用集合类型和选择集合类。
注意
对于本文中的示例,可能需要为 和 System.Collections.Generic 命名空间添加 System.Linq。
数组由 System.Array 表示,并受 C# 语言语法支持。 此语法为数组变量提供了更简洁的声明。
System.Span
Memory
从 C# 12 开始,可以使用集合表达式初始化所有集合类型。
可索引集合
可索引集合 是一个可以使用其索引访问每个元素的集合。 其索引是序列中在它之前的元素数。 因此,按索引 0 引用的元素是第一个元素,索引 1 则是第二个元素,依此而行。 这些示例使用 List
以下示例会创建和初始化字符串列表、移除元素并将元素添加到列表末尾。 每次修改后,它会使用 foreach 语句或 for 循环来循环访问字符串:
// Create a list of strings by using a
// collection initializer.
List
// 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
以下示例会从一个泛型列表中按索引移除元素。 它使用以降序进行循环访问的 foreach 语句,而不是 for 语句。
RemoveAt 方法将导致已移除元素后的元素索引值减小。
List
// 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
对于 List
private static void IterateThroughList()
{
var theGalaxies = new List
{
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; }
}
有关索引的详细信息,请参阅 “浏览索引和范围 ”一文。
键/值对集合
这些示例使用 Dictionary
以下示例创建 Dictionary 集合并通过使用 foreach 语句循环访问字典。
private static void IterateThruDictionary()
{
Dictionary
foreach (KeyValuePair
{
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
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}}
};
以下示例使用 ContainsKey 方法和 Item[] 的 Dictionary 属性按键快速查找某个项。 使用 Item 属性可通过 C# 中的 elements 来访问 elements[symbol] 集合中的项。
if (elements.ContainsKey(symbol) == false)
{
Console.WriteLine(symbol + " not found");
}
else
{
Element theElement = elements[symbol];
Console.WriteLine("found: " + theElement.Name);
}
与之相反,以下示例使用 TryGetValue 方法按键快速查找某个项。
if (elements.TryGetValue(symbol, out Element? theElement) == false)
Console.WriteLine(symbol + " not found");
else
Console.WriteLine("found: " + theElement.Name);
迭代器
迭代器用于对集合执行自定义迭代。 迭代器可以是一种方法,或是一个 get 访问器。 迭代器使用 yield return 语句返回集合的每一个元素,每次返回一个元素。
通过使用 foreach 语句调用迭代器。
foreach 循环的每次迭代都会调用迭代器。 迭代器中到达 yield return 语句时,会返回一个表达式,并保留当前在代码中的位置。 下次调用迭代器时,将从该位置重新开始执行。
有关详细信息,请参阅迭代器 (C#)。
下面的示例使用迭代器方法。 迭代器方法具有位于 yield return 循环中的 for 语句。 在 ListEvenNumbers 方法中,foreach 语句体的每次迭代都会创建对迭代器方法的调用,并将继续到下一个 yield return 语句。
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 firstNumber, int lastNumber)
{
// Yield even numbers in the range.
for (var number = firstNumber; number <= lastNumber; number++)
{
if (number % 2 == 0)
{
yield return number;
}
}
}
LINQ 和集合
可以使用语言集成查询 (LINQ) 来访问集合。 LINQ 查询提供筛选、排序和分组功能。 有关详细信息,请参阅 C# 中的 LINQ 入门。
以下示例运行一个对泛型 List 的 LINQ 查询。 LINQ 查询返回一个包含结果的不同集合。
private static void ShowLINQ()
{
List
// 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
{
{ 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}}
};