18.9.3迭代变量
回顾一下,foreach语句和for语句的区别之一就是,foreach使用了迭代变量。迭代变量是只读的,代码清单18-13将不能通过编译。
代码清单18-13 迭代变量是只读的
1 namespace ProgrammingCSharp4
2{
3 class Person
4{
5 public int Age{get;set;
6
7 public override string ToString()
8{
9 return string.Format(“年龄:{0}”,Age);
10}
11}
12
13 class ArraySample
14{
15 public static void Main()
16{
17 Person[]array1={new Person{Age=10},new Person{Age=20},new Person{Age=30}};
18
19 foreach(Person person in array1)
20{
21 person=new Person{Age=40};//错误
22 System.Console.WriteLine(person);
23}
24}
25}
26}
在上述代码中,试图给迭代变量person赋值,编译器将抛出如下异常:
"person"是一个“foreach迭代变量”,无法为它赋值
接下来,我们对出错的第21行稍加改造,如代码清单18-14所示。
代码清单18-14 通过迭代变量改变对象的值
foreach(Person person in array1)
{
person.Age=50;
System.Console.WriteLine(person);
}
程序正常运行了。运行结果如下:
年龄:50
年龄:50
年龄:50
接下来,我们分析一下为什么代码清单18-13编译出错,而代码清单18-14却能正常编译。因为person变量在这里是一个引用类型的变量,那么在代码清单18-13中向person变量赋值,就是传递引用,就是改变person变量的指向,由原来作为“数据1”的引用改成作为“数据2”的引用,这是不允许的,因为person变量只读;而在代码清单18-14中,是通过引用来改变数据的值,并没有改变引用本身,因此是合法的,其原理如图18-19所示。
图 18-19 对于两段代码的原理分析
总结一下,之所以可以通过迭代变量改变数据的值,是因为数组中的数据元素是引用类型,因此迭代变量是引用类型,引用类型的引用和数据分别位于栈和堆,这时的迭代变量实际上是位于栈中的一个引用,只要引用不改变,就可以通过引用改变数据。而对于值类型,值类型的值和变量名都位于栈中,我们无法改变值类型数组的数据。