[英]Class and List<> Reference Type in c#
我在以下有关案例1和案例2的代码中有一些疑问
在CASE-1中,我们分配的是obj1=null
,但是在obj2中,复制的值仍为i = 10。
在CASE-2中,我们在List
执行某些操作,但是一个列表中更改的值会影响另一个List
的值。
这背后的逻辑是什么,因为两者都是引用类型。
情况1
Class A
{
public int i;
}
A obj1 = new A();
obj1.i =10;
A obj2 = obj1;
obj1 = null;
案例2
List<int> test1 = new List<int>();
test1.Add(101);
List<int> test2 = test1;
test1.Add(201);
两者的逻辑都很简单:
A obj2
和List<int> test2
都引用与A obj1
和List<int> test1
相同的类型
这意味着您执行以下操作时:
Class A
{
public int i;
}
A obj1 = new A();
obj1.i =10;
A obj2 = obj1;
obj1 = null;
obj2
的值将被分配为obj1
的值,但它是它自己的对象,它没有成为obj1
,而是引用了他。 obj2
成为类型为A
的新对象,并在obj1
分配了值。
当您分配obj1=null
obj2
将不会受到影响,因为它的值已被分配。
但是,如果将其更改为:
obj1 = null;
A obj2 = obj1;
那么obj2
将为null,因为obj2
现在正在引用一个空对象。
情况2的情况相同:
List<int> test2
引用List<int> test1
,并将为其分配值。 结果是这段代码:
List<int> test1 = new List<int>();
test1.Add(101);
List<int> test2 = test1;
test1.Add(201);
将在test2中产生以下项目:
101
201
您可以在Microsoft文档中进一步阅读本文中的引用类型。 它相当扩展,几乎涵盖了所有内容。
那时使用new关键字时,将要分配一些内存,并且根据类型引用类型和值类型,它会在堆中分配,也可能是堆栈。 (可能将值类型分配给堆,并且它完全取决于CLR)
引用类型和值类型之间的区别在于,引用类型保留对在堆中创建的特定对象的(地址)的引用。 在值类型中,变量将保留值。
现在在您的情况下1 A a = new A(); //此时,已分配的内存和已分配的内存位置地址已分配给变量a。
A a1 = a; //此时,将创建新变量a1,该变量指向堆中与变量a相同的地址位置。
a = null; //此时,变量a设置为null意味着它与分配的实际对象的链接是在删除堆之后分配的。
但是a1仍然保留引用,因此它可以访问值
在情况2中(这也是引用类型的情况)//您的变量test1和test2不同,但是从堆保存的地址相同。
//因此,如果您更改任何项目,则两个变量都将指向同一位置,因此会受到影响。
//现在,如果您执行test1 = null,那么test2也会执行相同的操作,但是您无法通过test1进行访问,因为它现在为null。
obj1 = null;
从obj1
对对象的引用已被删除。 由于obj2
该对象仍然存在。
代替
test1 = null;
执行List<int>
上的方法:
test1.Add(201);
test1
和test2
仍指向同一List<int>
,因此列表中的更改可见。
我认为Barr J的答案是一个很好的答案,我不确定您是否会找到我的帮助,但是这些东西可能会令人困惑,以至于我认为值得尝试以稍有不同的方式解释正在发生的事情。
A obj1 = new A(); // 1.1
obj1.i = 10; // 1.2
A obj2 = obj1; // 1.3
obj1 = null; // 1.4
在第1.1行上, new
运算符创建引用类型A
的实例,而=
运算符将对该实例的引用存储在名为obj1
的变量中。 为了了解您的代码发生了什么,重要的是要区分引用 (存储在obj1
的值)和引用 (该值所引用的对象,该对象存储在其他位置)之间。
在第1.2行中, .
运算符用于取消对obj1
中存储的引用的引用—换句话说,以访问其引用对象(即您在1.1行创建的A
的实例)。 这使您可以访问该实例的字段i
并将其分配为10。
1.3 obj1
存储在obj1
的引用复制到另一个名为obj2
变量中。 现在,您有两个具有相同参照物的参照物。 这意味着obj2.i
也等于10,因为表达式obj1.i
和obj2.i
引用的值完全相同。
1.4 obj1
空引用存储到obj1
。 1.2和1.4行之间的关键区别在于,在1.4行上没有发生取消引用,因此您不会以任何方式影响引用对象。 您要做的只是将对对象的引用替换为对任何对象的引用。
现在考虑第二个示例中的代码:
List<int> test1 = new List<int>(); // 2.1
test1.Add(101); // 2.2
List<int> test2 = test1; // 2.3
test1.Add(201); // 2.4
第2.1–2.3行类似于第一个示例中的对应行:它们构造了List<int>
的实例和对该实例的两个引用,这些引用存储在List<T>
类型的两个变量test1
和test2
。 但是第2.4行是不同的:第1.4行将一个引用替换为另一个,而第2.4行则使用.
操作员再次访问test1
的引用对象并更新其内容。
无论您是通过test1
存储的引用还是通过test2
存储的引用访问该值,您都将在列表中看到值201,因为这两个引用具有相同的引用; 换句话说,您只创建了一个列表。
obj1
和test1
都是引用类型的变量,就像指针一样。 他们存储对其数据(对象)的引用 。 obj1
和obj2
引用相同的对象,但是它们是不同的变量。 因此,为obj1
分配null不会更改数据(对象)。 test1
和test2
也是不同的变量,但是test1.Add
和test2.Add
调用它们都引用的同一对象的相同方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.