[英]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.