博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
艾伟_转载:对于C#中b=a的N种情况分析
阅读量:5842 次
发布时间:2019-06-18

本文共 2492 字,大约阅读时间需要 8 分钟。

  本文旨在验证一个容易混淆的概念,从而为《玩转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);

            输出结果:

           

            再考察一下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中。

      示例代码下载:

转载于:https://www.cnblogs.com/waw/archive/2011/08/29/2157086.html

你可能感兴趣的文章
使用Dockerfile构建镜像
查看>>
大学生IT博客大赛开赛 相关报道
查看>>
tcpdump使用方法总结
查看>>
What is Cluster Aware Updating in Windows Server 2012?
查看>>
Linux命令详解 -- tar
查看>>
Java.net.URL学习总结
查看>>
Tracert(跟踪路由)是路由跟踪实用程序,用于确定 IP 数据包访问目标所采取的路径。...
查看>>
进老男孩的自我介绍和决心书
查看>>
Leetcode Construct Binary Tree from Inorder and Postorder Traversal
查看>>
基于Cat的分布式调用追踪
查看>>
线上Linux服务器运维安全策略经验分享
查看>>
Django实现组合搜索的方法示例
查看>>
Android一些问题的解决方案
查看>>
Clion 常用快捷键
查看>>
ios之UIToolBar
查看>>
10道典型的JavaScript面试题
查看>>
centos 6.5 docker  安装
查看>>
依然前往
查看>>
C++静态局部对象
查看>>
Hibernate用JPA注解 CascadeType.REMOVE 不起作用的解决办法
查看>>