繁体   English   中英

C#中的Class和List <>引用类型

[英]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 obj2List<int> test2都引用与A obj1List<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文档中进一步阅读本文中的引用类型。 它相当扩展,几乎涵盖了所有内容。

  1. 那时使用new关键字时,将要分配一些内存,并且根据类型引用类型和值类型,它会在堆中分配,也可能是堆栈。 (可能将值类型分配给堆,并且它完全取决于CLR)

  2. 引用类型和值类型之间的区别在于,引用类型保留对在堆中创建的特定对象的(地址)的引用。 在值类型中,变量将保留值。

  3. 现在在您的情况下1 A a = new A(); //此时,已分配的内存和已分配的内存位置地址已分配给变量a。

    A a1 = a; //此时,将创建新变量a1,该变量指向堆中与变量a相同的地址位置。

    a = null; //此时,变量a设置为null意味着它与分配的实际对象的链接是在删除堆之后分配的。

    但是a1仍然保留引用,因此它可以访问值

  4. 在情况2中(这也是引用类型的情况)//您的变量test1和test2不同,但是从堆保存的地址相同。

    //因此,如果您更改任何项目,则两个变量都将指向同一位置,因此会受到影响。

    //现在,如果您执行test1 = null,那么test2也会执行相同的操作,但是您无法通过test1进行访问,因为它现在为null。

情况1

obj1 = null;

obj1对对象的引用已被删除。 由于obj2该对象仍然存在。

CASE-2

代替

test1 = null;

执行List<int>上的方法:

test1.Add(201);

test1test2仍指向同一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.iobj2.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>类型的两个变量test1test2 但是第2.4行是不同的:第1.4行将一个引用替换为另一个,而第2.4行则使用. 操作员再次访问test1的引用对象并更新其内容。

无论您是通过test1存储的引用还是通过test2存储的引用访问该值,您都将在列表中看到值201,因为这两个引用具有相同的引用; 换句话说,您只创建了一个列表。

obj1test1都是引用类型的变量,就像指针一样。 他们存储对其数据(对象)的引用 obj1obj2引用相同的对象,但是它们是不同的变量。 因此,为obj1分配null不会更改数据(对象)。 test1test2也是不同的变量,但是test1.Addtest2.Add调用它们都引用的同一对象的相同方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM