艾伟_转载:对于C#中b=a的N种情况分析

简介:   本文旨在验证一个容易混淆的概念,从而为《玩转WPF/Silverlight中INotifyPropertyChanged和ObservableCollection》做铺垫。  两个相同类型的变量a和b,并且有如下关系:       b = a;  如果a发生改变,b是否也发生改变呢?   情况很复杂,分以下几种情况谈论:      1) 单个实体            1.

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

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

      b  =  a;

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

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

      1) 单个实体

            1. 简单类型

            先考察int:

             int  a  =   1 ;
            
int  b  =  a;

            a 
=   2 ;
            Console.WriteLine(
" b:  "   +  b);

            输出结果:

            clip_image002

            再考察一下string:

             string  a  =   " 1 " ;
            
string  b  =  a;

            a 
=   " 2 " ;
            Console.WriteLine(
" b:  "   +  b);

            输出结果:

            clip_image002[1]

            如果不放心,还可以测试一下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);

            输出结果:

            clip_image004

            结论: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);

            输出结果:

            clip_image006

            结论:对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);

            输出结果:

            clip_image008

            结论:问题集中在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);

            输出结果:

            clip_image010

            结论:b随着a中数据增减修改而变化。因为b和a指向托管堆上同一个List实例的内存地址,这和复合类型是一样的。

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

      示例代码下载:TestEqual.zip

目录
相关文章
|
11天前
|
安全 算法 测试技术
C#编程实战:项目案例分析
【4月更文挑战第20天】本文以电子商务系统为例,探讨C#在实际项目中的应用。通过面向对象编程实现组件抽象和封装,确保代码的可维护性和可扩展性;利用安全性特性保护用户数据;借助数据库操作处理商品信息;通过逻辑控制和算法处理订单;调试工具加速问题解决,展现C#的优势:面向对象、数据库交互、数据安全和开发效率。C#在实际编程中展现出广泛前景。
|
jenkins 关系型数据库 MySQL
一文搞定SonarQube接入C#(.NET)代码质量分析
一文搞定SonarQube接入C#(.NET)代码质量分析
1227 0
一文搞定SonarQube接入C#(.NET)代码质量分析
|
存储 C# 开发工具
C#编程的构成要素(结合unity做实例分析)
C#编程的构成要素(结合unity做实例分析)
C#编程的构成要素(结合unity做实例分析)
|
存储 NoSQL C#
基于C#的ArcEngine二次开发44: GDB矢量文件检查结果导出GDB/SHP的思路分析
基于C#的ArcEngine二次开发44: GDB矢量文件检查结果导出GDB/SHP的思路分析
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)(三)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)(三)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)(二)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)(二)
|
搜索推荐 C# 索引
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)(一)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)
基于C#的ArcEngine二次开发42:空间分析接口及分析(ITopologicalOperator / IRelationalOperator / IProximityOperator)(一)
|
存储 缓存 API
基于C#的ArcEngine二次开发36: 在地理数据库中创建要素类的接口及方法分析(下)
基于C#的ArcEngine二次开发36: 在地理数据库中创建要素类的接口及方法分析(下)
基于C#的ArcEngine二次开发36: 在地理数据库中创建要素类的接口及方法分析(下)
|
存储 NoSQL C#
基于C#的ArcEngine二次开发36: 在地理数据库中创建要素类的接口及方法分析(上)
基于C#的ArcEngine二次开发36: 在地理数据库中创建要素类的接口及方法分析
基于C#的ArcEngine二次开发36: 在地理数据库中创建要素类的接口及方法分析(上)
基于C#的ArcEngine二次开发35:缓冲区分析
基于C#的ArcEngine二次开发35:缓冲区分析
基于C#的ArcEngine二次开发35:缓冲区分析