本文旨在验证一个容易混淆的概念,从而为《玩转WPF/Silverlight中INotifyPropertyChanged和ObservableCollection》做铺垫。
两个相同类型的变量a和b,并且有如下关系:
如果a发生改变,b是否也发生改变呢?
情况很复杂,分以下几种情况谈论:
1) 单个实体
1. 简单类型
先考察int:
int a = 1 ; int b = a; a = 2 ; Console.WriteLine( " b: " + b); 输出结果:
再考察一下string:
string a = " 1 " ; string b = a; a = " 2 " ; Console.WriteLine( " b: " + b); 输出结果:
如果不放心,还可以测试一下Enum,结果类似,详见Demo。
结论:简单类型是组成复合类型的最基本单位,是原子,不可再拆分,所以不管是值类型double、int还是引用类型string,b都不随a的改变而改变,因为它们指向全局堆栈(对于string而言是托管堆)上的同一个地址。
2. 复合类型
复合类型是由string、int、double这些简单类型组成的。
分别定义一个复合的引用类型(class)和一个复合的值类型(struct)。
class UserInfo { public string UserName; public int Age; } struct UserInfo2 { public string UserName; public int Age; } 先讨论引用类型:
UserInfo a = new UserInfo() { UserName = " Baobao " , Age = 27 }; UserInfo b = a; a.UserName = " AndersLiu " ; a.Age = 30 ; Console.WriteLine( " b.UserName: " + b.UserName); Console.WriteLine( " b.Age: " + b.Age); 输出结果:
结论:b和a仍然指向托管堆上的同一个UserInfo实例的地址。而UserInfo实例的成员又包含着UserName和Age分别在托管堆和全局堆栈上的地址。所以修改a的成员UserName和Age,只是改变这两个成员的地址,而没有改变UserInfo实例的地址,所以b的成员UserName和Age也会跟着改变。
让我们局部修改上面的代码:
UserInfo a = new UserInfo() { UserName = " Baobao " , Age = 27 }; UserInfo b = a; // a.UserName = "AndersLiu"; // a.Age = 30; a = new UserInfo() { UserName = " AndersLiu " , Age = 30 }; Console.WriteLine( " b.UserName: " + b.UserName); Console.WriteLine( " b.Age: " + b.Age); 输出结果:
结论:对a重新进行实例化,导致a指向一个新的UserInfo实例的地址。而b仍然指向原先那个UserInfo实例的地址,所以b不会随着a的改变而改变。从此b和a是两个没有任何关系的变量。
再来看一下值类型:
UserInfo2 a = new UserInfo2() { UserName = " Baobao " , Age = 27 }; UserInfo2 b = a; a.UserName = " AndersLiu " ; a.Age = 30 ; Console.WriteLine( " b.UserName: " + b.UserName); Console.WriteLine( " b.Age: " + b.Age); 输出结果:
结论:问题集中在b=a这句话上。这时b指向的是a的一份copy,指向全局堆栈上的与a不同的地址。所以b和a是没有任何关系的,b不随a的改变而改变。
2) 集合
1.集合中一笔数据的增删修改。
List < UserInfo > a = new List < UserInfo > (); List < UserInfo > b = a; a.Add( new UserInfo() { UserName = " Baobao " , Age = 27 }); Console.WriteLine( " b.Count after adding: " + b.Count); Console.WriteLine(); Console.WriteLine( " After modifying a[0] " ); a[ 0 ].UserName = " AndersLiu " ; a[ 0 ].Age = 30 ; Console.WriteLine( " b[0].UserName: " + b[ 0 ].UserName); Console.WriteLine( " b[0].Age: " + b[ 0 ].Age); Console.WriteLine(); a.Remove(a[ 0 ]); Console.WriteLine( " b.Count after deleting: " + b.Count); 输出结果:
结论:b随着a中数据增减修改而变化。因为b和a指向托管堆上同一个List实例的内存地址,这和复合类型是一样的。
数组就不说了,可以看作是多个变量的集合,所以按照集合来处理。写了几段测试代码,放在Demo中。
示例代码下载: