对于C#中b=a的N种情况分析

本文旨在验证一个容易混淆的概念,从而为《玩转WPF/Silverlight中INotifyPropertyChanged和ObservableCollection》做铺垫。

  两个相同类型的变量a和b,并且有如下关系: 

  b = a;

  如果a发生改变,b是否也发生改变呢?

  情况很复杂,分以下几种情况谈论:

  1) 单个实体

        1. 简单类型

        先考察int:

双击代码全选
1
2
3
4
int  a = 1;
int  b = a;
a = 2;
Console.WriteLine( "b: "  + b);

        输出结果:

  

        再考察一下string:

双击代码全选
1
2
3
4
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)。 

双击代码全选
1
2
3
4
5
6
7
8
9
10
class  UserInfo
{
     public   string  UserName;
     public   int  Age;
}
struct  UserInfo2
{
     public   string  UserName;
     public   int  Age;
}

  先讨论引用类型: 

双击代码全选
1
2
3
4
5
6
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也会跟着改变。

        让我们局部修改上面的代码:

双击代码全选
1
2
3
4
5
6
7
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是两个没有任何关系的变量。

        再来看一下值类型: 

双击代码全选
1
2
3
4
5
6
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.集合中一笔数据的增删修改。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
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<UserInfo>实例的内存地址,这和复合类型是一样的。

  数组就不说了,可以看作是多个变量的集合,所以按照集合来处理。写了几段测试代码,放在Demo中。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值