Интересно о C#: странное поведение структур

понедельник, 22 февраля 2010, Александр Краковецкий

Рассмотрим следующий код:

struct S
{
  private string blah;
  public S(string blah)
  {
      this.blah = blah;
  }
  public void Frob()
  { // whatever
  }
}

Следующий код будет работать:

S s1 = new S();
s1.Frob();

Каждая струкура имеет конструктор по умолчанию, в котором все поля иницилизируются со значениями по умолчанию. А как насчет этого кода?

S s2;
s2.Frob();

Похоже, мы увидем ошибку "Use of unassigned local variable 's2'". Интересной особенностью C# компилятора является тот факт, что ошибка присвоения будет выдана лишь в том случае, если структура компилируется с исходного кода. В случае, если структура находится в подключенной библиотеке, ошибка не будет выдана! Рассмотрим другой пример:

struct SS
{
  public int x;
  public int y;
  public void Bar() {…}
}

Рассмотрим код, который использует структуру:

SS ss;
ss.x = 123;
ss.y = 456;
ss.Bar();

Вы не поверите, но этот код посностью рабочий! Локальная переменная s имеет две переменных - x и у. Если обоим переменным x и y присвоены значения, то s считается проинициализированной. Если был вызван конструктор, то все переменные автоматически инициализируются, в противном случае компилятор проверяет, все ли переменные структуры проинициализированны и если это так - не выдает ошибку.

Аномалия происходит по той причине, что когда компилятор видит структуру в исходном коде, то он проверяет все переменные и находит, что s1.blah не проинициализирована и выдает ошибку, что s1 также не проинициализирована. Но в случае, когда структура находится в библиотеке, компилятор игнорирует недоступные поля ссылочного типа. Выходит, что ни одно из полей не было проинициализировано из нуля доступных полей, которые необходимо инициализировать, но s1 все равно должна быть проинициализирована!

Замечание. Компилятор игнорирует лишь недоступные поля ссылочного типа, в том время когда численные типы проверяются.

Это поведение, несомненно, является странным. Думаю, что мы должны быть последовательными и либо рассматривать постоянно все поля, либо рассматривать только доступные поля все время, а не бегать вперед-назад в зависимости деталей процесса компиляции. Мой выбор был бы первым - заставлять пользователя вызывать конструктор по умолчанию или конструктор default(T). Данное поведение не является критическим, но было бы неплохо иметь одинаковое поведение.

Источник

P.S. Если вы заметили какие-либо неточности при переводе, прошу сообщить.


Ищите нас в интернетах!

Комментарии

Свежие вакансии