簡體   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