2011-02-05 96 views
5

有人可以解釋一下,在值類型內定義引用類型時會發生什麼。 我寫了下面的代碼:類內部結構

namespace ClassInsideStruct 
{ 
    class ClassInsideStruct 
    { 
     static void Main(string[] args) 
     { 

      ValueType ObjVal = new ValueType(10); 
      ObjVal.Display(); 

      ValueType.ReferenceType ObjValRef = new ValueType.ReferenceType(10); 
      ObjValRef.Display(); 

      Test(ObjVal, ObjValRef); 

      ObjVal.Display(); 
      ObjValRef.Display(); 

      Console.ReadKey(); 

     } 

     private static void Test(ValueType v, ValueType.ReferenceType r) 
     { 
      v.SValue = 50; 
      r.RValue = 50; 
     } 

    } 

    struct ValueType 
    { 

     int StructNum; 
     ReferenceType ObjRef; 

     public ValueType(int i) 
     { 
      StructNum = i; 
      ObjRef = new ReferenceType(i); 
     } 

     public int SValue 
     { 
      get { return StructNum; } 
      set 
      { 
       StructNum = value; 
       ObjRef.RValue = value; 
      } 
     } 

     public void Display() 
     { 
      Console.WriteLine("ValueType: " + StructNum); 
      Console.Write("ReferenceType Inside ValueType Instance: "); 
      ObjRef.Display(); 
     } 

     public class ReferenceType 
     { 

      int ClassNum; 

      public ReferenceType(int i) 
      { 
       ClassNum = i; 
      } 

      public void Display() 
      { 
       Console.WriteLine("Reference Type: " + ClassNum); 
      } 

      public int RValue 
      { 
       get { return ClassNum; } 
       set { ClassNum = value; } 
      } 

     } 

    } 

} 

,輸出:

 
ValueType: 10 
ReferenceType Inside ValueType Instance: Reference Type: 10 
Reference Type: 10 
ValueType: 10 
ReferenceType Inside ValueType Instance: Reference Type: 50 
Reference Type: 50 

我很好奇地想知道,調用它位於裏面的方法Test(ObjVal, ObjValRef)ReferenceType值如何更改爲50後價值沒有改變的ValueType

+1

類到所述結構的位置是無關緊要的。它只是一個嵌套類型(在C#中 - 與Java或Scala不同 - 它不依賴於封閉類型)。它與'ReferenceType`不是*嵌套的語義相同。不要將類型和變量與給定類型的實例化對象混淆。 – 2011-02-05 07:23:13

回答

2

我並不確定,但編譯器可能會將代碼分離爲單獨的類,然後只執行所需的規則。當您使用值類型時,每次將其傳入方法時都會複製該值。對引用類型的引用將被複制,但引用同一個對象。同樣的參考對象將被更改,而複製的值類型將被更改。您傳入的原稿不會反映副本上的更改。

+0

+1我喜歡明確提到「複製」的方式。這個要求保留了結構類型的調用語義與實際實現無關。 – 2011-02-05 07:25:30

1

價值裏面值類型是參考,它沒有改變。但是,參考文獻指出的價值可以很容易地改變。

2

由於引用類型是引用類型,值類型是值類型。無論他們在哪裏居住。

而且值類型不會更改,也不會更改引用其持有。 其變更的參考類型(仔細閱讀我的文字)。

即即將改變該地址的基礎數據。值類型的引用仍然相同。

+0

我喜歡這個開始。也許澄清解釋`對象t = Guid.New; f(t)` – 2011-02-05 07:21:22

+0

@pst它不是New是Guid.NewGuid。它返回一個值類型GUID結構則是盒裝入對象和引用給定爲t ... BTW什麼是F()做... – 2011-02-05 09:17:14

1

引用類型作爲指針傳入方法,所以修改內容將修改內存中的相同位置。通過在調用堆棧上發送值,將值類型傳遞到方法中。編程時

+1

和指針發出...達姆達姆達姆...作爲在堆棧上的價值!這個答案是不是不正確,但要實現大的「差異化」這一點很重要的是,語義是這樣的:*引用類型對象的無可複製/重複*時,它的傳遞完成(這包括*取消*值類型)。值類型的對象*可以*也可以通過「引用」傳遞,如果它是這樣的複製/克隆來保存語義;實施僅僅是實施。 – 2011-02-05 07:19:58

-1

,是要明白,調用接受參數的方法是很重要的意味着/包括/相同分配值,這些參數。加上:

static void Main(string[] args) 
{ 

    ValueType ObjVal = new ValueType(10); 
    ObjVal.Display(); 

    ValueType.ReferenceType ObjValRef = new ValueType.ReferenceType(10); 
    ObjValRef.Display(); 

    //call to Test(ObjVal, ObjValRef); replaced by the following 4 lines 
    ValueType v = ObjVal; 
    ReferenceType r = ObjValRef; 
    v.SValue = 50; 
    r.RValue = 50; 

    ObjVal.Display(); 
    ObjValRef.Display(); 

    Console.ReadKey(); 

} 

應該給出與上例相同的結果。當你聲明ValueType v = ObjVal;您正在製作實際結構對象的副本,這意味着v是一個單獨的對象。所以改變它的成員值不會影響ObjVal。

然而,ReferenceType r = ObjValRef;的副本作爲參考。所以現在有兩個引用,ObjValRefr,指向同一個對象。即調用時創建的新對象ValueType.ReferenceType(10);

所以當對象的變更部件指向通過任何這兩篇參考文獻的,該對象的變化,無論哪個指針被用於執行的變化。

哦,由by ..引用只是一個對象的地址。通常這是一個32位的數字,但是這個從語言到語言,從處理器到處理器都在變化。

和本身改變參考副本,例如r = null;不會影響「原始」引用ObjValRef,因爲r是ObjValRef的副本,而不是ObjValRef本身。它看起來好像是相同的,因爲它們都指向同一個對象。

你能想到的實際對象作爲一個地方(一個公園或一些著名的建築,也許「白色山公園」),並引用內容指向這個地方路牌的。可以有許多指向同一地點的路牌,但這並不意味着有許多「白色山地公園」。這是值類型和引用類型之間的差異。