数组
可以将同一类型的多个变量存储在一个数组数据结构中。 通过指定数组的元素类型来声明数组。 如果希望数组存储任意类型的元素,可将其类型指定为 object
。 在 C# 的统一类型系统中,所有类型(预定义类型、用户定义类型、引用类型和值类型)都是直接或间接从 Object 继承的。
type[] arrayName;
数组具有以下属性:
- 数组可以是一维、多维或交错的。
- 声明数组变量时设置维度数。 创建数组实例时,将建立每个维度的长度。 这些值在实例的生存期内无法更改。
- 交错数组是数组数组,每个成员数组的默认值为
null
。 - 数组从零开始编制索引:包含
n
元素的数组从0
索引到n-1
。 - 数组元素可以是任何类型,其中包括数组类型。
- 数组类型是从抽象的基类型 Array 派生的引用类型。 所有数组都会实现IList和IEnumerable。 可以使用 foreach 语句循环访问数组。 单维数组还实现了 IList<T> 和 IEnumerable<T>。
创建数组时,可以将数组的元素初始化为已知值。 从 C# 12 开始,可以使用集合表达式初始化所有集合类型。 未初始化的元素设置为默认值。 默认值为 0 位模式。 所有引用类型(包括不可为 null的类型)都具有值null
。 所有值类型都有 0 位模式。 这意味着Nullable<T>.HasValue属性为false
且Nullable<T>.Value属性未定义。 在 .NET 实现中,Value
属性引发异常。
下面的示例创建一维数组、多维数组和交错数组:
// Declare a single-dimensional array of 5 integers.
int[] array1 = new int[5];
// Declare and set array element values.
int[] array2 = [1, 2, 3, 4, 5, 6];
// Declare a two dimensional array.
int[,] multiDimensionalArray1 = new int[2, 3];
// Declare and set array element values.
int[,] multiDimensionalArray2 = { { 1, 2, 3 }, { 4, 5, 6 } };
// Declare a jagged array.
int[][] jaggedArray = new int[6][];
// Set the values of the first array in the jagged array structure.
jaggedArray[0] = [1, 2, 3, 4];
重要
本文中的许多示例使用集合表达式(使用方括号)来初始化数组。 集合表达式最初在 C# 12 中引入,该版本随 .NET 8 发布。 如果尚无法升级到 C# 12,请改用 {
和 }
初始化数组。
// Collection expressions:
int[] array = [1, 2, 3, 4, 5, 6];
// Alternative syntax:
int[] array2 = {1, 2, 3, 4, 5, 6};
一维数组
一维数组是一系列相似元素。 可以通过其索引访问元素。 索引是序列中的顺序位置。 数组中的第一个元素位于索引0
。 使用 new 运算符创建一维数组,该运算符指定数组元素类型和元素数目。 以下示例声明并初始化一维数组:
int[] array = new int[5];
string[] weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
Console.WriteLine(weekDays[0]);
Console.WriteLine(weekDays[1]);
Console.WriteLine(weekDays[2]);
Console.WriteLine(weekDays[3]);
Console.WriteLine(weekDays[4]);
Console.WriteLine(weekDays[5]);
Console.WriteLine(weekDays[6]);
/*Output:
Sun
Mon
Tue
Wed
Thu
Fri
Sat
*/
第一个声明声明五个整数的未初始化数组,从array[0]
到array[4]
。 数组元素将初始化为元素类型的默认值,0
代表整数。 第二个声明声明字符串数组并初始化该数组的所有七个值。 一系列 Console.WriteLine
语句打印 weekDay
数组的所有元素。 对于一维数组,foreach
语句以递增索引顺序处理元素(从索引 0 开始并以索引Length - 1
结束)。
将一维数组作为参数传递
可将初始化的一维数组传递给方法。 在下面的示例中,先初始化一个字符串数组,然后将其作为参数传递给字符串的 DisplayArray
方法。 该方法将显示数组的元素。 接下来,ChangeArray
方法会反转数组元素,然后由 ChangeArrayElements
方法修改该数组的前三个元素。 每个方法返回后,DisplayArray
方法会显示按值传递数组不会阻止对数组元素的更改。
class ArrayExample
{
static void DisplayArray(string[] arr) => Console.WriteLine(string.Join(" ", arr));
// Change the array by reversing its elements.
static void ChangeArray(string[] arr) => Array.Reverse(arr);
static void ChangeArrayElements(string[] arr)
{
// Change the value of the first three array elements.
arr[0] = "Mon";
arr[1] = "Wed";
arr[2] = "Fri";
}
static void Main()
{
// Declare and initialize an array.
string[] weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
// Display the array elements.
DisplayArray(weekDays);
Console.WriteLine();
// Reverse the array.
ChangeArray(weekDays);
// Display the array again to verify that it stays reversed.
Console.WriteLine("Array weekDays after the call to ChangeArray:");
DisplayArray(weekDays);
Console.WriteLine();
// Assign new values to individual array elements.
ChangeArrayElements(weekDays);
// Display the array again to verify that it has changed.
Console.WriteLine("Array weekDays after the call to ChangeArrayElements:");
DisplayArray(weekDays);
}
}
// The example displays the following output:
// Sun Mon Tue Wed Thu Fri Sat
//
// Array weekDays after the call to ChangeArray:
// Sat Fri Thu Wed Tue Mon Sun
//
// Array weekDays after the call to ChangeArrayElements:
// Mon Wed Fri Wed Tue Mon Sun
多维数组
数组可具有多个维度。 例如,以下声明创建四个数组:两个具有两个维度,两个具有三个维度。 前两个声明声明每个维度的长度,但不初始化数组的值。 第二个声明使用初始值设定项设置多维数组中每个元素的值。
int[,] array2DDeclaration = new int[4, 2];
int[,,] array3DDeclaration = new int[4, 2, 3];
// Two-dimensional array.
int[,] array2DInitialization = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// Three-dimensional array.
int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };
// Accessing array elements.
System.Console.WriteLine(array2DInitialization[0, 0]);
System.Console.WriteLine(array2DInitialization[0, 1]);
System.Console.WriteLine(array2DInitialization[1, 0]);
System.Console.WriteLine(array2DInitialization[1, 1]);
System.Console.WriteLine(array2DInitialization[3, 0]);
System.Console.WriteLine(array2DInitialization[3, 1]);
// Output:
// 1
// 2
// 3
// 4
// 7
// 8
System.Console.WriteLine(array3D[1, 0, 1]);
System.Console.WriteLine(array3D[1, 1, 2]);
// Output:
// 8
// 12
// Getting the total count of elements or the length of a given dimension.
var allLength = array3D.Length;
var total = 1;
for (int i = 0; i < array3D.Rank; i++)
{
total *= array3D.GetLength(i);
}
System.Console.WriteLine($"{allLength} equals {total}");
// Output:
// 12 equals 12
对于多维数组,遍历元素的方式为:首先递增最右边维度的索引,然后是它左边的一个维度,以此类推,向最左的索引遍历元素。 以下示例枚举 2D 和 3D 数组:
int[,] numbers2D = { { 9, 99 }, { 3, 33 }, { 5, 55 } };
foreach (int i in numbers2D)
{
System.Console.Write($"{i} ");
}
// Output: 9 99 3 33 5 55
int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };
foreach (int i in array3D)
{
System.Console.Write($"{i} ");
}
// Output: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
在 2D 数组中,可以将左索引视为行,将右索引视为列。
但对于多维数组,使用嵌套的for循环可以更好地控制处理数组元素的顺序:
int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
{ { 7, 8, 9 }, { 10, 11, 12 } } };
for (int i = 0; i < array3D.GetLength(0); i++)
{
for (int j = 0; j < array3D.GetLength(1); j++)
{
for (int k = 0; k < array3D.GetLength(2); k++)
{
System.Console.Write($"{array3D[i, j, k]} ");
}
System.Console.WriteLine();
}
System.Console.WriteLine();
}
// Output (including blank lines):
// 1 2 3
// 4 5 6
//
// 7 8 9
// 10 11 12
//
将多维数组作为参数传递
通过与传递一维数组相同的方式,向方法传递初始化的多维数组。 下列代码演示了 Print 方法的部分声明(该方法接受将二维数组作为其参数)。 可在同一步骤中初始化并传递新数组,如下例所示。 在下列示例中,初始化一个整数的二维数组,并将其传递至 Print2DArray
方法。 该方法将显示数组的元素。
static void Print2DArray(int[,] arr)
{
// Display the array elements.
for (int i = 0; i < arr.GetLength(0); i++)
{
for (int j = 0; j < arr.GetLength(1); j++)
{
System.Console.WriteLine("Element({0},{1})={2}", i, j, arr[i, j]);
}
}
}
static void ExampleUsage()
{
// Pass the array as an argument.
Print2DArray(new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } });
}
/* Output:
Element(0,0)=1
Element(0,1)=2
Element(1,0)=3
Element(1,1)=4
Element(2,0)=5
Element(2,1)=6
Element(3,0)=7
Element(3,1)=8
*/
交错数组
交错数组是一个数组,其元素是数组,大小可能不同。 交错数组有时称为“数组的数组”。其元素是引用类型,初始化为null
。 以下示例说明如何声明、初始化和访问交错数组。 第一个示例jaggedArray
在一个语句中声明。 每个包含的数组在后续语句中创建。 第二个示例jaggedArray2
在一个语句中声明和初始化。 可以混合使用交错数组和多维数组。 最终示例jaggedArray3
是一维交错数组声明和初始化,包含大小不同的三个二维数组元素。
int[][] jaggedArray = new int[3][];
jaggedArray[0] = [1, 3, 5, 7, 9];
jaggedArray[1] = [0, 2, 4, 6];
jaggedArray[2] = [11, 22];
int[][] jaggedArray2 =
[
[1, 3, 5, 7, 9],
[0, 2, 4, 6],
[11, 22]
];
// Assign 77 to the second element ([1]) of the first array ([0]):
jaggedArray2[0][1] = 77;
// Assign 88 to the second element ([1]) of the third array ([2]):
jaggedArray2[2][1] = 88;
int[][,] jaggedArray3 =
[
new int[,] { {1,3}, {5,7} },
new int[,] { {0,2}, {4,6}, {8,10} },
new int[,] { {11,22}, {99,88}, {0,9} }
];
Console.Write("{0}", jaggedArray3[0][1, 0]);
Console.WriteLine(jaggedArray3.Length);
必须先初始化交错数组的元素,然后才能使用它们。 每个元素本身都是数组。 还可以使用初始值设定项填充数组元素的值。 使用初始值设定项时,无需数组大小。
本例生成一个数组,该数组的元素为数组自身。 每一个数组元素都有不同的大小。
// Declare the array of two elements.
int[][] arr = new int[2][];
// Initialize the elements.
arr[0] = [1, 3, 5, 7, 9];
arr[1] = [2, 4, 6, 8];
// Display the array elements.
for (int i = 0; i < arr.Length; i++)
{
System.Console.Write("Element({0}): ", i);
for (int j = 0; j < arr[i].Length; j++)
{
System.Console.Write("{0}{1}", arr[i][j], j == (arr[i].Length - 1) ? "" : " ");
}
System.Console.WriteLine();
}
/* Output:
Element(0): 1 3 5 7 9
Element(1): 2 4 6 8
*/
隐式类型的数组
可以创建隐式类型化的数组,其中数组实例的类型通过数组初始值设定项中指定的元素来推断。 针对隐式类型化变量的任何规则也适用于隐式类型化数组。 有关详细信息,请参阅隐式类型局部变量。
下列示例演示了如何创建隐式类型化数组:
int[] a = new[] { 1, 10, 100, 1000 }; // int[]
// Accessing array
Console.WriteLine("First element: " + a[0]);
Console.WriteLine("Second element: " + a[1]);
Console.WriteLine("Third element: " + a[2]);
Console.WriteLine("Fourth element: " + a[3]);
/* Outputs
First element: 1
Second element: 10
Third element: 100
Fourth element: 1000
*/
var b = new[] { "hello", null, "world" }; // string[]
// Accessing elements of an array using 'string.Join' method
Console.WriteLine(string.Join(" ", b));
/* Output
hello world
*/
// single-dimension jagged array
int[][] c =
[
[1,2,3,4],
[5,6,7,8]
];
// Looping through the outer array
for (int k = 0; k < c.Length; k++)
{
// Looping through each inner array
for (int j = 0; j < c[k].Length; j++)
{
// Accessing each element and printing it to the console
Console.WriteLine($"Element at c[{k}][{j}] is: {c[k][j]}");
}
}
/* Outputs
Element at c[0][0] is: 1
Element at c[0][1] is: 2
Element at c[0][2] is: 3
Element at c[0][3] is: 4
Element at c[1][0] is: 5
Element at c[1][1] is: 6
Element at c[1][2] is: 7
Element at c[1][3] is: 8
*/
// jagged array of strings
string[][] d =
[
["Luca", "Mads", "Luke", "Dinesh"],
["Karen", "Suma", "Frances"]
];
// Looping through the outer array
int i = 0;
foreach (var subArray in d)
{
// Looping through each inner array
int j = 0;
foreach (var element in subArray)
{
// Accessing each element and printing it to the console
Console.WriteLine($"Element at d[{i}][{j}] is: {element}");
j++;
}
i++;
}
/* Outputs
Element at d[0][0] is: Luca
Element at d[0][1] is: Mads
Element at d[0][2] is: Luke
Element at d[0][3] is: Dinesh
Element at d[1][0] is: Karen
Element at d[1][1] is: Suma
Element at d[1][2] is: Frances
*/
在上个示例中,请注意对于隐式类型化数组,初始化语句的左侧没有使用方括号。 此外,和一维数组一样,通过使用new []
来初始化交错数组。
创建包含数组的匿名类型时,必须在类型的对象初始值设定项中隐式类型化数组。 在下列示例中,contacts
是匿名类型的隐式类型化数组,每个类型都包含名为PhoneNumbers
的数组。 不在对象初始值设定项中使用var
关键字。
var contacts = new[]
{
new
{
Name = "Eugene Zabokritski",
PhoneNumbers = new[] { "206-555-0108", "425-555-0001" }
},
new
{
Name = "Hanying Feng",
PhoneNumbers = new[] { "650-555-0199" }
}
};