緣由:
“A PRoperty method may require additional memory or return a reference to something
that is not actually part of the object’s state, so modifying the returned object has no
effect on the original object; querying a field always returns a reference to an object
that is guaranteed to be part of the original object’s state . Working with a property
that returns a copy can be very confusing to developers, and this characteristic is frequently not documented .“
這段話源自《CLR via C#》第4版中第十章 屬性 。
這段話主要意思是:一個屬性方法(指的是自動屬性的get方法)可能要求額外的內存,另外返回的引用實際上不是對象的狀態的一部分(意思是返回的不是對象的成員字段的引用),所以修改返回值不會影響原來的對象;查詢字段通常返回引用,該引用可以保證是原來的對象的狀態的一部分。屬性返回的是copy,這會讓開發者感到困惑,而且這種情況通常沒有被記載在文檔中。
我為了驗證這段話中”查詢字段通常返回引用,該引用可以保證是原來的對象的狀態的一部分“,寫了個Demo。
聲明一個類型Student,
成員:
3個字段:Int32類型的no、String類型的str、Object類型的obj;
3個查詢字段的方法: 返回Int32的方法GetNo()、返回String類型的方法GetStr()、返回Object類型的方法GetObj(
class Student { internal Int32 no = 1;internal Object obj = new Object(); internal Int32 GetNo() { return this.no; }internal Object GetObj() { return this.obj; } }
在控制臺的Main()方法中
static void Main(string[] args) { var s1 = new Student(); var no = s1.GetNo();//no的地址應該等于s1的成員no的地址 var obj = s1.GetObj();//obj的地址應該等于s1的成員obj的地址 Console.WriteLine(ReferenceEquals(no, s1.no));//使用靜態ReferenceEquals()方法判斷兩個變量是否相等,下同。 Console.WriteLine(ReferenceEquals(obj, s1.obj)); Console.Read(); }
驗證問題:
首先科普一下:
1、當聲明一個變量時,立刻就會在棧上面聲明該變量(入棧),該變量存儲方式應該是一個鍵值對(key:堆地址;value:變量的值,注意:如果是引用類型的話,這里就是在堆上的地址)。
2、在vs中調試→窗口→即時窗口,通過&+變量名,來觀察變量在棧中的情況。例如:
&s1.no //觀察變量s1的成員no
0x030c499c //鍵:棧上的地址。
*&s1.no: 1 //值:1。
&s1.obj //觀察變量s1的成員obj
0x030c4998 //鍵:棧上的地址。
*&s1.obj: {51136932} //值:在堆上的地址。//如果是*&s1.obj: {0},那么就表示未在堆上開辟空間,值為null。
執行下程序,進行觀察,結果如下:
觀察的結果完全符合ReferenceEquals()的結果。
那么這個通過方法獲取返回值的過程是什么樣的呢?我用下圖模擬下變量在內存中發生的過程。
那么到這里,也就證明了查詢字段獲取的返回值,確實是對象狀態的一部分。
新聞熱點
疑難解答