问题描述
如下图所示,query1是个集合,把它赋值给了query2,当移除query2里面数据的时候,query1对应的数据也被移除了。
原因分析:
对此猜测是引用类型的问题,类似于浅拷贝深拷贝那种概念。
基础概念:
对于上述的情况,要怎么去赋值,以及不同的写法对应的结果是什么样的呢,我做了如下测试 ,在看结果之前,先了解一下相关概念。
C#中的堆和栈:(指的是程序运行时的内存区域)
内存分为堆区域和栈区域,栈空间比较小,但是读取速度快(先进后出),堆空间比较大,但是读取速度慢。
栈区:存放函数的参数,局部变量,返回数据等值,会自动释放。
堆区:存放着引用类型的对象,会由GC来自动释放。
值类型和引用类型
值类型:在方法传递的时候,传递的是自身的“拷贝”。
(例如:结构体struct,数据类型short/int/double/bool,枚举类型enum,可空类型)引用类型:引用类型则是传递的自身的“地址”。
( 例如:数组,类,接口,委托,object,string)
值类型只需要一段单独的内存(此处指栈区内存),用于存储实际的数据。
引用类型需要两段内存,第一段存储实际的数据,位于堆中。第二段是一个引用,存储在栈里,指向数据在堆中的存放位置。
特点:
1、值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
2、引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new
创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
3、值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。(某些情况指的是:作为字段时,跟随其所属的变量(实例)存储;作为局部变量时,存储在栈上。)
4、引用类型的对象总是在进程堆中分配(动态分配)。
本地测试:
下图展示了4个list以及对应的赋值情况,从结果可以看出,list1、list3、list4的栈区内容都指向了同一个堆地址,所以当这三个list任意一个删除数据或添加数据,其他两个也会变化。而list2由于指向的堆地址跟其他三个不同,所以list2的数据变化不会影响到list1、list3、list4。
其中list4比较出乎我的意料,印象中list t=new list中的关键字new,会在托管堆上重新分配空间,并返回一个该空间的地址,但是从结果上来看,list4还是指向了list1的堆地址。猜测可能是编译器的自动优化?就像string的赋值那样?
下面是string的测试,图一是定义了三个变量,a、b、c,可以看出,a和b虽然是分别定义并且分别赋值的,但由于值一样,最终还是指向了同一个堆地址。而图二中,给a重新赋值后,发现它并没有去更改原地址中的数据,而是在堆中开辟了一块新的空间,并指向了这个新的堆地址(在栈中的地址没变)。
到此这篇关于C# List的赋值问题的解决的文章就介绍到这了,更多相关C# List赋值内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!