2010-10-13 47 views
7

可能有人請解釋這個結構V/S級在C#中 - 請解釋行爲

class testCompile 
    { 
     /* 
     * Sample Code For Purpose of Illustration 
     */ 
     struct person 
     { 
      public int age; 
      public string name; 

     } 

     static void Main(string[] args) 
     { 
      List<person> Listperson = new List<person>(); 
      person myperson = new person(); 

      for (int i = 1; i <= 2; i++) 
      { 
       //Assignment 
       myperson.age = 22+i; 
       myperson.name = "Person - " + i.ToString(); 
       Listperson.Add(myperson); 
      } 
      int x = 0; 
      while (x < Listperson.Count) 
      { 
       //Output values 
       Console.WriteLine("{0} - {1}", Listperson[x].name, Listperson[x].age); 
       x++; 
      } 
     } 
    } 

/* 
    Output: 
    Person - 1 - 23 
    Person - 2 - 24 
*/ 

爲什麼我沒有得到相同的輸出的一類作爲一個結構的行爲?

class testCompile 
    { 
     /* 
     * Sample Code For Purpose of Illustration 
     */ 
     class person 
     { 
      public int age; 
      public string name; 

     } 

     static void Main(string[] args) 
     { 
      List<person> Listperson = new List<person>(); 
      person myperson = new person(); 

      for (int i = 1; i <= 2; i++) 
      { 
       //Assignment 
       myperson.age = 22+i; 
       myperson.name = "Person - " + i.ToString(); 
       Listperson.Add(myperson); 
      } 
      int x = 0; 
      while (x < Listperson.Count) 
      { 
       //Output values 
       Console.WriteLine("{0} - {1}", Listperson[x].name, Listperson[x].age); 
       x++; 
      } 
     } 
    } 
/* 
    Output: 
    Person - 2 - 24 
    Person - 2 - 24 
*/ 
+0

這是因爲結構的實例在堆棧上分配,類的實例在堆上分配。咄。 – jason 2010-10-13 13:30:37

+1

@Jason:不,關於值類型與參考類型的存儲位置存在很多混淆。最好閱讀Eric的優秀博客文章:http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx – 2010-10-13 13:32:05

+0

@ 0xA3:你內心的笑話書呆子幽默探測器失敗。 – jason 2010-10-13 13:33:42

回答

17

類是參考類型,結構是類型。

類型傳遞到作爲參數的方法中,複製將傳遞。這意味着您需要添加兩個完全獨立的結構的副本,循環中的每個循環都有一個副本。

當一個參考類型作爲參數傳遞給方法,將參考將通過。這意味着您將兩個副本的引用副本添加到同一個內存位置(與同一個Person對象相同) - 更改此對象時,您會看到它反映在兩個引用中,因爲它們都引用同一個對象。

+0

@ 0xA3 - 謝謝你的答覆...更新,希望現在挑選出來) – Oded 2010-10-13 14:08:01

4

因爲你myperson變量永遠只與一個人的struct /類處理。

在循環中添加到列表中的是您的myperson變量的副本 - 對於結構體,它將是結構體的完整副本,但是該類將是參考文獻的副本到您創建(和變異)的單個實例。

1

在第二個示例中,您只是在項目上創建並多次添加對列表的引用。

5

這是值類型(結構)和引用類型(類)之間的差異。

  • 當你添加的結構來Listperson人的內容放在列表中,您的列表中有兩個不同的人結構。

    for (int i = 1; i <= 2; i++) 
    { 
        //Assignment 
        myperson.age = 22+i; 
        myperson.name = "Person - " + i.ToString(); 
        Listperson.Add(myperson); 
        /* First time: 
        Listperson contains a person struct with value { age = 23, name = 1} 
        Second iteration: 
        Listperson contains a person struct with value { age = 23, name = 1} 
        Listperson contains another person struct with value { age = 24, name = 2} 
        */ 
    } 
    
  • 當你將基準放置在列表中的類,你有引用同一個人對象兩個引用。

    for (int i = 1; i <= 2; i++) 
    { 
        //Assignment 
        myperson.age = 22+i; 
        myperson.name = "Person - " + i.ToString(); 
        Listperson.Add(myperson); 
        /* First time: 
        Listperson contains 1 reference to myperson object with value { age = 23, name = 1} 
        Second iteration: 
        Listperson contains 2 reference to myperson object with value { age = 24, name = 2} 
        */ 
    } 
    
2

在第二種情況下,你addding引用類型。實際上,您添加相同的商品,兩次,因爲您的

= new person() 

不在循環中。因此,它始終指向你在這裏初始化相同的對象:

person myperson = new person(); 

它添加到列表後,也改變影響它。

在第一個實例中,您每次都添加一個結構體,這是一個值類型,所以會被複制到列表中。之後所做的更改不再引用列表中的對象,因此它們具有不同的值。

1

將結構添加到集合時,它會複製它。這是一個值類型。您最終會收集兩個不同的對象,每個對象都有不同的值。這可能是預期的行爲。

當您將該類引用類型添加到集合中時,不會創建新對象。實際上,您將兩個不同的引用添加到同一個對象。你將最終得到(顯然)具有相同值的兩個對象。它實際上是同一個對象,看起來在集合中出現了兩次。

2

結構是值類型,類是參考類型。因此,在第一個示例中,當您將myperson添加到列表中時,添加myperson和myperson變量的副本仍然指向單獨的副本。在你的第二個例子中,myperson是一個引用類型,所以你將兩個指針添加到同一個對象。

2

您應該瞭解結構(Value Types)和類(Reference Type)之間的關鍵區別。您可以在GoogleSO中輕鬆找到此信息。

當您將結構實例添加到List時,您將爲此實例創建另一個獨立副本,並且當您更改一個元素時,您不會更改另一個元素。

但是在類的情況下,您創建一個實例並使用這個具有兩個引用(列表[0]和列表1)的「共享」實例,並且可以通過兩個不同的引用更改這一個實例,這就是爲什麼當您更改列表[0]項目似乎您也更改列表1項目。

考慮下面的代碼:

var s1 = new SampleStruct { X = 1, Y = 1 }; 
var s2 = s1; 
//Creating separate copy 
//Lets check this 
Console.WriteLine(object.ReferenceEquals(s1, s2)); //Prints False 

var c1 = new SampleClass { X = 1, Y = 2 }; 
var c2 = c1; 
//We do not create any copy 
// two references c1 and c2 "pointed" to one shared object 
Console.WriteLine(object.ReferenceEquals(c1, c2)); //Prints True 

類似行爲時,我們通過參數函數(或添加元素列出),我們有。

4

如果要相同的結果然後將人申報的內部for循環: -

  // person myperson = new person(); 
      //Move the upper line inside the for loop 
      for (int i = 1; i <= 2; i++) 
      { 
       person myperson = new person(); 
       //Assignment 
       myperson.age = 22+i; 
       myperson.name = "Person - " + i.ToString(); 
       Listperson.Add(myperson); 
      } 

在結構你將值相加型因此單獨的值被存儲,而在類您的對象添加參考因此獲得相同的價值。

+0

我意識到這一點。謝謝。 – abhi 2010-10-13 17:36:00

0

將類型的變量和參數看作持有「實例ID」。 (1)創建一個新的(將被分配給一個類的新實例),(2)將一個分配給另一個,或者(3)檢查兩個ID到看看他們是否平等。使用類別類型的變量,參數等進行其他操作時,只需簡單地將「指向該實例ID的實例」。

所以這樣的代碼:

 
{ 
    Car A,B,C; /* Car is a class */ 
    A = new Car; 
    B = new Car; 
    C = A; 
    A.color = carColors.Yellow; 
    B.color = C.color; 
} 

第一個「新」的語句將創建Car的實例,並把它的實例ID(假設#1234)在「A」。第二個將創建另一個汽車實例(#4321)並將其ID存儲在B中。接下來的語句將#1234複製到C中。它不會對汽車做任何事 - 它只是複製身份證。然後車號#1234將被塗成黃色,然後在最後的聲明中,#1234號車的顏色(即黃色)將被用來繪製車號#4321。請注意,雖然A和C是不同的變量,但它們都保持相同的實例ID(#1234),因此是指同一輛車。