C#中的struct v / s类 – 请解释一下这种行为

有人可以解释一下这种行为

class testCompile { /* * Sample Code For Purpose of Illustration */ struct person { public int age; public string name; } static void Main(string[] args) { List Listperson = new List(); 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 Listperson = new List(); 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 */ 

类是引用类型,结构是类型。

类型作为参数传递给方法时,将传递它的副本 。 这意味着您添加了两个完全独立Person结构副本 ,每个副本用于循环中的每个传递。

引用类型作为参数传递给方法时,将传递引用 。 这意味着您将引用的两个副本添加到同一个内存位置 (到同一个Person对象) – 当对这个对象进行更改时,您会看到它反映在两个引用中,因为它们都引用了同一个对象。

它是值类型(struct)和引用类型(class)之间的区别。

  • 当您将结构添加到Listperson ,person的内容将放入列表中,您的列表中有两个不同的person结构。

     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} */ } 

因为你的myperson变量只处理一个人结构/类。

你在循环中添加到列表中的是myperson变量的副本 – 对于struct,它将是struct的完整副本,但是对于类,将是您的单个实例的引用的副本创造(和变异)。

如果你想要相同的结果,那么在for循环中引入person声明: –

  // 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); } 

在struct中添加一个值类型,因此存储了单独的值,而在类中,您添加了对象的引用,因此获得相同的值。

在第二个实例中,您将添加引用类型。 事实上,你要添加两次相同的项目,因为你的

  = new person() 

不在循环中。 所以它总是指向你在这里初始化的同一个对象:

  person myperson = new person(); 

即使它已添加到您的列表中,更改也会影响它。

在第一个实例中,您每次都添加一个结构,这是一个值类型,因此将被复制到列表中。 在此之后所做的更改不再引用列表中的对象,因此它们具有不同的值。

结构是值类型,类是引用类型。 因此,在第一个示例中,当您将myperson添加到列表中时,添加myperson的副本和myperson变量仍然引用单独的副本。 在第二个示例中,myperson是一个引用类型,因此您添加两个指向同一对象的指针。

您应该了解结构( 值类型 )和类( 引用类型 )之间的关键区别。 您可以在Google或SO上轻松找到此信息。

将结构实例添加到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 

当我们将参数传递给函数(或将元素添加到列表)时,我们有类似的行为。

在第二个示例中,您只是在项目上创建并多次添加对列表的引用。

将结构添加到集合时,它会复制它。 这是一种价值类型 。 您最终会在集合中使用两个不同的对象,每个对象具有不同的值。 这可能是预期的行为。

将类( 引用类型)添加到集合时,不会创建新对象。 您实际上是在同一个对象中添加了两个不同的引用。 你最终会得到(显然)具有相同值的两个对象。 它实际上是同一个对象,似乎在集合中出现了两次。

将类类型的变量和参数视为持有“实例ID”。 实际上可以直接用实例ID做的事情是(1)创建一个新的(将被分配给一个新的类实例),(2)将一个分配给另一个,或者(3)检查两个ID到看他们是否平等。 使用类类型的变量,参数等执行任何其他操作都是“对引用此实例ID的实例执行_ ”的简写。

所以代码如下:

 {
  车A,B,C;  / *汽车是一类* /
   A =新车;
   B =新车;
   C = A;
   A.color = carColors.Yellow;
   B.color = C.color;
 }

第一个“new”语句将创建Car的实例并将其实例ID(假设#1234)放在“A”中。 第二个将创建另一个汽车实例(#4321)并将其ID存储在B中。下一个语句将#1234复制到C中。它对汽车没有任何作用 – 它只是复制ID。 然后汽车#1234将被涂成黄色,然后在最后一个陈述中,汽车#1234(即黄色)的颜色将用于涂漆汽车#4321。 请注意,虽然A和C是不同的变量,但它们都拥有相同的实例ID(#1234),因此引用同一辆车。