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

时间:2010-10-13 13:17:36

标签: c# .net class struct

有人可以解释一下这个

的行为
  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 
*/

10 个答案:

答案 0 :(得分:17)

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

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

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

答案 1 :(得分:5)

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

  • 当你将结构添加到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 :(得分:4)

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

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

答案 3 :(得分:4)

如果你想要相同的结果,那么在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中添加值类型因此存储了单独的值,而在类中,您添加了对象的引用,因此得到相同的值。

答案 4 :(得分:2)

在第二个实例中,您要添加引用类型。事实上,自你的

以来,你要添加两次相同的项目
  = new person()

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

 person myperson = new person();

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

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

答案 5 :(得分:2)

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

答案 6 :(得分:2)

你应该理解结构(Value Types)和类(Reference Type)之间的关键区别。您可以在GoogleSO

中轻松找到此信息

将结构实例添加到List时,您为此实例创建另一个单独的副本,当您更改一个元素时,您没有更改另一个元素。

但是在类的情况下,你创建一个实例并使用这个“共享”实例和两个引用(list [0]和list 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

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

答案 7 :(得分:1)

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

答案 8 :(得分:1)

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

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

答案 9 :(得分:0)

将类类型的变量和参数视为持有“实例ID”。实际上可以直接使用实例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;
}

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