Что я делаю не так с инициализаторами объектов C #? - PullRequest
7 голосов
/ 18 февраля 2009

Когда я инициализирую объект, используя новые инициализаторы объектов в C #, я не могу использовать одно из свойств в классе для выполнения дальнейших действий, и я не знаю, почему.

Мой пример кода:

Person person = new Person { Name = "David", Age = "29" };

В классе Person x будет равно 0 (по умолчанию):

public Person()
{
  int x = Age; // x remains 0 - edit age should be Age. This was a typo
}

Однако, человек. Возраст равен 29. Я уверен, что это нормально, но я хотел бы понять, почему.

Ответы [ 6 ]

21 голосов
/ 18 февраля 2009

Свойства устанавливаются для Name и Age после завершения работы конструктора public Person ().

Person person = new Person { Name = "David", Age = "29" };

эквивалентно

Person tempPerson = new Person()
tempPerson.Name = "David";
tempPerson.Age = "29";
Person person = tempPerson;

Итак, в конструкторе Age еще не станет 29.

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


Если вы хотите иметь возможность манипулировать свойством Age в конструкторе, тогда я предлагаю вам создать конструктор, который принимает в качестве аргумента возраст:

public Person(string name, int age)
{
   Name = name;
   Age = age;

   // Now do something with Age
   int x = Age;
   // ...
}
9 голосов
/ 18 февраля 2009

Обратите внимание, как важная техническая деталь, что:

Person person = new Person { Name = "David", Age = "29" };

эквивалентно:

Person <>0 = new Person(); // a local variable which is not visible within C#
<>0.Name = "David";
<>0.Age = "29";
Person person = <>0;

но не эквивалентно:

Person person = new Person();
person.Name = "David";
person.Age = "29";
6 голосов
/ 18 февраля 2009

Ваша строка кода идентична:

Person person = new Person() { Name = "David", Age = "29" };

, что идентично:

Person person = new Person();
person.Name = "David";
person.Age = "29";

Как видите; когда конструктор выполняется, Age еще не установлено.

4 голосов
/ 18 февраля 2009

Технически, этот код:

Person person = new Person { Name = "David", Age = 29 };

идентичен этому коду:

Person tmpPerson = new Person();
tmpPerson.Name = "David";
tmpPerson.Age = 29;
Person person = tmpPerson;

, что немного отличается от того, что опубликовали другие:

Person person = new Person();
person.Name = "David";
person.Age = 29;

Это различие крайне важно, если ваше приложение использует многопоточность.

3 голосов
/ 18 февраля 2009

Похоже, вы пытаетесь получить доступ к Age в конструкторе объекта. Значения инициализатора объекта не будут установлены до тех пор, пока не будет выполнен конструктор.

Попробуйте это:

Person person = new Person { Name = "David", Age = 29 };
int x = person.Age;

РЕДАКТИРОВАТЬ в ответ на комментарий

Если вам нужен доступ к Age в самом конструкторе, вам нужно создать явный конструктор с необходимыми параметрами и использовать его вместо синтаксиса инициализатора объекта. Например:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public Person(string name, int age)
    {
        Name = name;
        Age = age;

        int x = Age;  // will be 29 in this example
    }
}

Person person = new Person("David", 29);
0 голосов
/ 18 февраля 2009

Ну, как говорили другие, сначала был запущен конструктор без параметров, отсюда и ваше затруднение.

Однако я должен спросить, если вы задали поле вместо автоматического свойства для переменной Age?

public class Person
{
    private int _age;

    public int Age
    {
        get { return _age; }
        set { _age = value; }
    }
 }

Вы можете использовать _age вместо x, если этого достаточно, или если вам действительно нужно использовать x:

public class Person
{
    private int _age;
    private int x;

    public int Age
    {
        get { return _age; }
        set 
        { 
            _age = value;
            x = _age;
        }
    }
 }

В зависимости от того, что больше подходит.

...