集合 - C# reference

集合 - C# reference

.NET 运行时提供了许多集合类型,用于存储和管理相关对象的组。 某些集合类型(例如 System.Array, System.Span)以 System.MemoryC# 语言识别。 此外,类似 System.Collections.Generic.IEnumerable 的接口可使用枚举集合元素的语言来识别。

集合提供灵活的方式来使用对象组。 可按以下特征对不同的集合进行分类:

元素访问:可以枚举每个集合以按顺序访问每个元素。 某些集合可通过索引(元素在有序集合中的位置)访问元素。 最常见的示例是 System.Collections.Generic.List。 其他集合可按键访问元素,其中值与单个键相关联。 最常见的示例是 System.Collections.Generic.Dictionary。 可根据应用访问元素的方式在这些集合类型之间进行选择。

性能配置文件:每个集合都有不同的性能配置文件,可用于添加元素、查找元素或移除元素等操作。 可以根据应用中最常用的操作选取集合类型。

动态增长和收缩:大多数集合支持动态添加或移除元素。 需要注意的是,Array、System.Span 和 System.Memory 不支持。

除了这些特征之外,运行时还提供专用集合,这些集合可阻止添加或移除元素,或修改集合的元素。 其他专用集合为多线程应用中的并发访问提供安全性。

可以在 .NET API 参考中找到所有集合类型。 有关其他信息,请参阅常用集合类型和选择集合类。

注意

对于本文中的示例,可能需要为 和 System.Collections.Generic 命名空间添加 System.Linq。

数组由 System.Array 表示,并受 C# 语言语法支持。 此语法为数组变量提供了更简洁的声明。

System.Span 属于 ref struct 类型,它可提供一系列元素的快照,而无需复制这些元素。 编译器强制实施安全规则,以确保在它引用的序列不再存在于作用域内之后无法访问 Span。 它用于许多 .NET API 以提高性能。

Memory 可在无法使用 ref struct 类型时提供类似的行为。

从 C# 12 开始,可以使用集合表达式初始化所有集合类型。

可索引集合

可索引集合 是一个可以使用其索引访问每个元素的集合。 其索引是序列中在它之前的元素数。 因此,按索引 0 引用的元素是第一个元素,索引 1 则是第二个元素,依此而行。 这些示例使用 List 类。 它是最常见的可索引集合。

以下示例会创建和初始化字符串列表、移除元素并将元素添加到列表末尾。 每次修改后,它会使用 foreach 语句或 for 循环来循环访问字符串:

// Create a list of strings by using a

// collection initializer.

List 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

以下示例会从一个泛型列表中按索引移除元素。 它使用以降序进行循环访问的 foreach 语句,而不是 for 语句。

RemoveAt 方法将导致已移除元素后的元素索引值减小。

List 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

对于 List 中的元素类型,还可以定义自己的类。 在下面的示例中,由 Galaxy 使用的 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 elements = BuildDictionary();

foreach (KeyValuePair 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 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}}

};

以下示例使用 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 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 和集合

可以使用语言集成查询 (LINQ) 来访问集合。 LINQ 查询提供筛选、排序和分组功能。 有关详细信息,请参阅 C# 中的 LINQ 入门。

以下示例运行一个对泛型 List 的 LINQ 查询。 LINQ 查询返回一个包含结果的不同集合。

private static void ShowLINQ()

{

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

};

相关创作

“炁”是什么?艺术中的“炁”是如何表达的?
365bet现金信誉网

“炁”是什么?艺术中的“炁”是如何表达的?

📅 08-06 👁️ 5394
《我的前半生》在上海哪里拍摄取景的?子君小说结局是什么?
下载365APP手机客户端

《我的前半生》在上海哪里拍摄取景的?子君小说结局是什么?

📅 08-30 👁️ 3086
《怪物猎人 荒野》全武器派生表
365bet现金信誉网

《怪物猎人 荒野》全武器派生表

📅 07-17 👁️ 5430