Подтвердить что ты не робот

Почему я должен инициализировать все поля в моей структуре С# с помощью конструктора без значения по умолчанию?

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

public struct Direction
{
   private int _azimuth;

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

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

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

Спасибо.

4b9b3361

Ответ 1

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

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

new BimonthlyPairStruct()

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

См. также: CLR через С# 2nd Ed - Pg 188

Ответ 2

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

public struct Direction
{
    public int Azimuth { get; private set; }

    public Direction(int azimuth) : this()
    {
        Azimuth = azimuth;
    }
}

Ответ 6

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