Struct v / s Class в C # - Пожалуйста, объясните поведение - PullRequest
7 голосов
/ 13 октября 2010

Может кто-нибудь объяснить, пожалуйста, поведение этого

  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 ]

17 голосов
/ 13 октября 2010

Классы ссылки типы, структуры значения типы.

Когда тип value передается методу в качестве параметра, будет передаваться copy его. Это означает, что вы добавляете две полностью отдельные копии структуры Person, по одной на каждый проход в цикле.

Когда тип ссылки передается методу в качестве параметра, ссылка будет передаваться. Это означает, что вы добавляете две копии ссылки в одну и ту же область памяти (к одному и тому же Person объекту) - при внесении изменений в этот один объект вы видите, что это отражено в обеих ссылках, поскольку они обе ссылаются тот же объект.

5 голосов
/ 13 октября 2010

Это разница между типом значения (структура) и ссылочным типом (класс).

  • Когда вы добавляете структуру к 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} 
      */
    }
    
  • Когда вы добавляете класс, ссылка помещается в список, у вас есть две ссылки, ссылающиеся на один и тот же объект 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 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} 
      */
    }
    
4 голосов
/ 13 октября 2010

Если вы хотите получить тот же результат, тогда приведите объявление лица внутри цикла 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);
            }

В структуре вы добавляете тип значения, следовательно, отдельные значения сохраняются, тогда как в классе вы добавляете ссылку наобъект, следовательно, получает то же значение.

4 голосов
/ 13 октября 2010

Поскольку ваша переменная myperson имеет дело только с одной структурой / классом person.

То, что вы добавляете в список в своем цикле, является копией вашей переменной myperson, которая для структуры будетполная копия структуры, но для класса будет копия ссылки на единственный экземпляр, который вы создаете (и изменяете).

2 голосов
/ 13 октября 2010

Вы должны понимать ключевые различия между структурами ( Типы значений ) и классами ( Тип ссылки ).Вы можете легко найти эту информацию в Google или в SO .

Когда вы добавляете экземпляр структуры в список, вы создаете другую отдельную копию для этого экземпляра, а также приодин элемент, который вы не изменили, другой.

Но в случае классов вы создаете один экземпляр и используете этот «общий» экземпляр с двумя ссылками (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

Подобное поведение мы имеем, когда передаем параметр в функцию (или добавляем элемент в список).

2 голосов
/ 13 октября 2010

Структуры являются типами значений, а классы являются ссылочными типами. Итак, в вашем первом примере, когда вы добавляете myperson в список, вы добавляете копию myperson и переменную myperson по-прежнему ссылаетесь на отдельную копию. Во втором примере myperson является ссылочным типом, поэтому вы добавляете два указателя к одному и тому же объекту.

2 голосов
/ 13 октября 2010

Во втором случае вы добавляете ссылочный тип. На самом деле, вы добавляете один и тот же элемент дважды, поскольку ваш

  = new person()

не в цикле. Так что он всегда указывает на тот же объект, который вы инициализировали здесь:

 person myperson = new person();

Даже после добавления в ваш список изменения влияют на него.

В первом случае вы каждый раз добавляете структуру, которая является типом значения, поэтому будет скопирована в список. Изменения, которые вы вносите после этого, больше не относятся к объекту в списке, поэтому они имеют разные значения.

1 голос
/ 13 октября 2010

Когда вы добавляете структуру в коллекцию, она делает ее копию.Это тип значения .В итоге вы получите два разных объекта в коллекции, каждый из которых имеет разные значения.Вероятно, это ожидаемое поведение.

При добавлении класса, ссылочного типа , в коллекцию новый объект не создается.Вы фактически добавляете две разные ссылки на один и тот же объект.Вы получите (очевидно) два объекта с одинаковым значением.На самом деле это один и тот же объект, который, кажется, дважды появляется в коллекции.

1 голос
/ 13 октября 2010

Во втором примере вы создаете только элемент и добавляете ссылку на список много раз.

0 голосов
/ 13 октября 2010

Представьте, что переменные и параметры типов классов содержат «идентификаторы экземпляров». Единственное, что можно сделать непосредственно с идентификатором экземпляра, это (1) создать новый (который будет назначен новому экземпляру класса), (2) назначить один другому или (3) проверить два идентификатора посмотрим, равны ли они. Делать что-либо еще с переменной, параметром и т. Д. Типа класса - это сокращение от "do _ до экземпляра, указанного в этом экземпляре 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 и поместит его идентификатор экземпляра (скажем, # 1234) в «A». Второй создаст другой экземпляр автомобиля (# 4321) и сохранит его идентификатор в B. Следующий оператор скопирует # 1234 в C. Он ничего не делает с автомобилем - он просто копирует идентификатор. Затем автомобиль № 1234 будет окрашен в желтый цвет, а затем в последнем утверждении цвет автомобиля № 1234 (т.е. желтый) будет использоваться для окраски автомобиля № 4321. Обратите внимание, что, хотя A и C являются разными переменными, они оба содержат один и тот же идентификатор экземпляра (# 1234) и, следовательно, ссылаются на одну и ту же машину.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...