练习 - 了解 Clear() 和 Resize()
- 15 分钟
在您继续为物流公司开发托盘追踪器的过程中,可能需要跟踪新托盘,并从跟踪系统中移除旧托盘。 那么如何创建允许添加和移除托盘的跟踪功能呢?
使用数组方法清除数组并调整其大小
使用 Array.Clear() 方法可以清除数组中特定元素的内容,从而将其替换为数组的默认值。 例如,如果清除 string 数组中的元素,则清除的值将替换为 null。 同样,在清除 int 数组中的元素时,将替换为 0(零)。
另一方面,使用 Array.Resize() 方法可以从数组中添加或移除元素。
删除或使用行注释运算符
//注释掉前面步骤中的所有代码。在 Visual Studio Code 编辑器中更新代码,如下所示:
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Array.Clear(pallets, 0, 2); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }注意
此示例使用 C# 12 中引入的 Collection 表达式语法。
花点时间了解代码行
Array.Clear(pallets, 0, 2);。此处,使用
Array.Clear()方法来清除存储在pallets数组元素中的值(从索引0开始,清除2个元素)。在 Visual Studio Code 的“文件”菜单上,选择“保存”。
在生成或运行代码之前,必须保存 Program.cs 文件。
在“资源管理器”面板中,若要在 TestProject 文件夹位置打开终端,请右键单击“TestProject”,然后选择“在集成终端中打开”。
终端面板应打开,并应包含一个命令提示符,显示终端已打开转到 TestProject 文件夹位置。
在终端命令提示符处,若要运行代码,请键入 dotnet run,然后按 Enter。
注意
如果看到一条指示“找不到要运行的项目”的消息,请确保终端命令提示符显示预期的 TestProject 文件夹位置。 例如:
C:\Users\someuser\Desktop\csharpprojects\TestProject>运行代码时,你会发现清除了存储在数组内前两个元素中的值。在
Length属性和foreach语句中,这些元素仍然存在,但当前为空。Clearing 2 ... count: 4 -- -- -- B12 -- A13
空字符串与 null
使用 Array.Clear() 时,被清除的元素不再引用内存中的字符串。 事实上,该元素不指向任何内容。 “不指向任何内容”的概念非常重要,最初可能会难以理解。
如果尝试检索受 Array.Clear() 方法影响的某个元素的值,能检索到吗?
访问已清除元素的值
需要两种方法来确定已清除元素的值,以查看 C# 编译器如何处理 null 值。
在
Array.Clear(pallets, 0, 2);代码行周围插入新的代码行,如下所示:Console.WriteLine($"Before: {pallets[0]}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0]}");验证代码,应与以下代码列表一致:
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Console.WriteLine($"Before: {pallets[0]}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0]}"); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }保存代码文件,然后使用 Visual Studio Code 运行代码。
应会看到以下输出:
Before: B14 After: Clearing 2 ... count: 4 -- -- -- B12 -- A13
如果关注 After: 输出行,你可能会认为 pallets[0] 中存储的值是空字符串。 但是,C# 编译器会将 null 值隐式转换为可供显示的空字符串。
在已清除元素上调用字符串帮助程序方法
为了证明清除后存储在 pallets[0] 中的值为 null,将修改代码示例,在 ToLower() 上调用 pallets[0] 方法。 如果它是字符串,代码应会正常工作。 但如果它为 null,则会使代码引发异常。
若要在每次尝试将
ToLower()写入控制台时调用pallets[0]方法,请按如下所示更新代码:Console.WriteLine($"Before: {pallets[0].ToLower()}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0].ToLower()}");请确保代码与以下代码列表相匹配:
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Console.WriteLine($"Before: {pallets[0].ToLower()}"); Array.Clear(pallets, 0, 2); Console.WriteLine($"After: {pallets[0].ToLower()}"); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }保存代码文件,然后使用 Visual Studio Code 运行代码。 这次运行代码时,会看到一条很长的错误消息。 如果分析该文本,将看到以下消息:
System.NullReferenceException: Object reference not set to an instance of an object.引发此异常的原因是,尝试在
pallets[0]元素的内容上调用方法时,C# 编译器尚未将 null 隐式转换为空字符串。由此可知,
Array.Clear()会删除数组元素对值的引用(如果存在)。 若要解决此问题,可以在尝试输出值之前检查该值是否为 null。若要避免错误,可以在访问可能为 null 的数组元素之前添加
if语句。
if (pallets[0] != null)
Console.WriteLine($"After: {pallets[0].ToLower()}");
调整数组大小以添加更多元素
接下来,重写步骤 1 中的代码列表,在其中包含用于调整数组大小的代码。 完成后,代码应与以下代码列表一致:
string[] pallets = ["B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Array.Clear(pallets, 0, 2); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); } Console.WriteLine(""); Array.Resize(ref pallets, 6); Console.WriteLine($"Resizing 6 ... count: {pallets.Length}"); pallets[4] = "C01"; pallets[5] = "C02"; foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }花几分钟时间了解行
Array.Resize(ref pallets, 6);。此时将调用通过引用(使用
Resize()关键字)传入pallets数组的ref方法。 在某些情况下,方法会要求按值(默认)或按引用(使用 ref 关键字)来传递参数。 要解释此操作的必要性,需花时间详细阐释 .NET 中对象的管理方式。 很遗憾,这超出了本模块的范围。 如果有疑问,建议查看 Intellisense 或 Microsoft Docs,获取有关如何正确调用给定方法的示例。在本例中,要将
pallets数组从 4 个元素调整为6个。 将新元素添加到当前元素的末尾。 在向这两个新元素赋值之前,其值为 null。保存代码文件,然后使用 Visual Studio Code 运行代码。 运行代码后,应看到以下输出。
Clearing 2 ... count: 4 -- -- -- B12 -- A13 Resizing 6 ... count: 6 -- -- -- B12 -- A13 -- C01 -- C02
调整数组大小以删除元素
相反,可以使用 Array.Resize() 来删除数组元素。
在 Visual Studio Code 编辑器中更新代码,如下所示:
string[] pallets = [ "B14", "A11", "B12", "A13" ]; Console.WriteLine(""); Array.Clear(pallets, 0, 2); Console.WriteLine($"Clearing 2 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); } Console.WriteLine(""); Array.Resize(ref pallets, 6); Console.WriteLine($"Resizing 6 ... count: {pallets.Length}"); pallets[4] = "C01"; pallets[5] = "C02"; foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); } Console.WriteLine(""); Array.Resize(ref pallets, 3); Console.WriteLine($"Resizing 3 ... count: {pallets.Length}"); foreach (var pallet in pallets) { Console.WriteLine($"-- {pallet}"); }保存代码文件,然后使用 Visual Studio Code 运行代码。 运行代码,应看到以下输出:
Clearing 2 ... count: 4 -- -- -- B12 -- A13 Resizing 6 ... count: 6 -- -- -- B12 -- A13 -- C01 -- C02 Resizing 3 ... count: 3 -- -- -- B12请注意,调用
Array.Resize()不会删除前两个 null 元素, 而是删除了最后三个元素。 值得注意的是,即使最后三个元素包含字符串值,也会将其删除。
是否能从数组中删除 null 元素?
如果 Array.Resize() 方法不能从数组中删除空元素,是否存在其他可自动完成此作业的帮助程序方法? 否。 从数组删除空元素的最佳方式是,通过循环访问每个项并使一个变量(计数器)递增,对非 null 元素进行计数。 接下来,创建另一个与计数器变量大小相同的数组。 最后,循环访问原始数组中的每个元素,并将非 null 值复制到新数组中。
概括
以下是本单元中展示的几处重要内容:
- 使用
Clear()方法清空数组内元素中的值。 - 使用
Resize()方法更改数组中的元素数,从数组末尾删除或添加元素。 - 新的数组元素和已清除的元素为 null,这意味着它们不指向内存中的值。