Почему я должен инициализировать все поля в моей структуре C # конструктором не по умолчанию? - PullRequest
12 голосов
/ 06 апреля 2009

Я хотел бы попробовать этот код:

public struct Direction
{
   private int _azimuth;

   public int Azimuth
   {
     get { return _azimuth; }
     set { _azimuth = value; }
   }       

   public Direction(int azimuth)
   { 
      Azimuth = azimuth
   } 
}

Но это не удается при компиляции, я понимаю, что структура должна инициализировать все ее поля. но я пытаюсь понять, что происходит под капотами CLR \ IL. зачем нужны все поля перед любым другим методом \ property \ this и т. д.

Спасибо.

Ответы [ 6 ]

9 голосов
/ 25 апреля 2009

Типы значений создаются в стеке (если они не вложены в ссылочный тип). В полях / расположениях в стеке есть что-то, что CLR не может гарантировать, что они будут обнулены (в отличие от полей / местоположений в управляемом куча, которая гарантированно обнуляется). Следовательно, они должны быть записаны до того, как их прочитают. В противном случае это дыра в безопасности.

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

new BimonthlyPairStruct()

Однако, когда вы реализуете свой параметризованный ctor, вы должны убедиться, что все поля были инициализированы - что требуется, чтобы CLR передавал ваш код как безопасный / проверен .

См. Также: CLR via C # 2nd Ed - Pg 188

5 голосов
/ 06 апреля 2009

Я только что нашел объяснение на форуме MSDN , в котором говорится, что это правило применяется, поскольку обнуление памяти пропускается, если вы используете конструктор по умолчанию none. Таким образом, вы должны будете предоставить значения инициализации для всех полей, чтобы избежать некоторых полей, содержащих случайные значения. Этого легко добиться, вызывая конструктор по умолчанию без параметра, но за счет инициализации некоторых полей дважды.

Я не могу сказать, правильно ли это объяснение, но оно звучит разумно.

Когда вы определяете инициализатор не по умолчанию, C # требует, чтобы вы установили все поля, потому что пропускает обнуление памяти и позволяет инициализировать его - в противном случае вам понадобится двойной удар производительности инициализации. Если вы не заботитесь о (очень мало) снижение производительности вы всегда можете связать вызов инициализатора: this () и только тогда инициализировать выбранные поля.

5 голосов
/ 06 апреля 2009

Это работает:

  public Direction(int azimuth)
  {
    _azimuth = azimuth;
  }

Из спецификации:

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

По сути, компилятор должен видеть, что каждое поле инициализируется в конструкторе, чтобы он мог копировать эти значения, и он не хочет проверять вызовы функций или свойств.

5 голосов
/ 06 апреля 2009

Это потому, что структуры являются производными от System.ValueType, а не System.Object. System.ValueType реализует конструктор по умолчанию, который нельзя переопределить, этот конструктор по умолчанию инициализирует все поля в структуре со своим значением по умолчанию. Поэтому, если вы реализуете какой-либо параметр параметра в своем классе, вам также понадобится t0, чтобы убедиться, что вы вызываете system.ValueType по умолчанию const. И чтобы ответить, почему ему нужно инициализировать все свое значение, это потому, что значение хранится в памяти стека.

2 голосов
/ 06 апреля 2009
public struct Direction
{
    public int Azimuth { get; private set; }

    public Direction(int azimuth) : this()
    {
        Azimuth = azimuth;
    }
}
0 голосов
/ 06 апреля 2009

Вам нужно инициализировать поле, а не через свойство.

...