8

Если вы посмотрите на следующий пример:Почему локальная переменная C# должна быть назначена напрямую, даже если это значение по умолчанию?

public void TestLocalValuesAssignment() 
{ 
    int valueVariable; // = default(int) suits fine 
    string refType; // null suits fine as well 

    try 
    { 
     valueVariable = 5; 
     refType = "test"; 
    } 
    catch (Exception){} 

    Console.WriteLine("int value is {0}", valueVariable); 
    Console.WriteLine("String is {0}", refType); 
} 

вы можете легко увидеть, что переменные valueVariable и refType может быть Unassigned до их использования в Console.WriteLine(). Компилятор говорит нам о том, что с ошибками:

Error 1 Use of unassigned local variable 'valueVariable' 
Error 2 Use of unassigned local variable 'refType' 

Это широко распространенный случай и есть loads of answers о том, как исправить, что (возможные исправления комментировал).

Я не понимаю, почему такое поведение существует? Как здесь локальные переменные отличаются от полей классов, где последние получают значение по умолчанию, если не назначены (значение null для ссылочных типов и соответствующее значение по умолчанию для типов значений)? Может быть, есть пример или угловой случай, который объясняет, почему такое поведение компилятора выбрано?

+1

Возможный дубликат [Инициализация полей экземпляров по сравнению с локальными переменными] (http://stackoverflow.com/questions/1542824/initialization-of-instance-fields-vs-local-variables) –

+1

Это не «поведение», , это * правило *. В определенном правиле присваивания указывается, что перед тем, как он будет использоваться, должна быть назначена переменная *. Очевидно, что это не будет в вашем фрагменте кода, когда возникает исключение. Да, может случиться. –

+0

@TimSchmelter Полностью согласен, это дубликат. [Джон Скит предоставил] (http://stackoverflow.com/a/1542851/472020) довольно разумное объяснение, которое можно было бы рассматривать как ответ на мой вопрос. – Antonio

ответ

11

в основном - это то, что решил М.С.

Если вы хотите больше вы можете прочитать here и проверить Eric Lippert’s Blog

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

+1

Эта ссылка относится к большому ответу Эрика Липперта. –

+0

Согласен, ответ Эрика Липперта объясняет многое. В принципе, это, как представляется, правило для предотвращения ошибок программистов. – Antonio

+2

@ Антонио: Правильно. В принципе, идея состоит в том, что (1) неинициализированные переменные, вероятно, являются ошибками, и (2) очень легко обнаружить, когда локально не определенно назначено, но довольно сложно определить, когда поле определенно не определено , Таким образом, правило: locals должны быть определенно назначены. Если бы было дешево и легко находить поля, которые были неназначенными, это правило также будет распространено и на поля, но это не дешево и легко. –

4

Это описано в C# спецификации:

5.1.7 Локальные переменные

Локальная переменная введена в локальной-переменной декларации не автоматически инициализируются и таким образом, не имеет значение по умолчанию стоимость. Для целей проверки определенного присвоения локальная переменная, введенная посредством , объявляет локальную переменную первоначально не назначенной. локальной переменной декларации может включать в себя локальной переменной-инициализатору, в этом случае переменная считается определенно присвоенной только после инициализации выражения (§5.3.3.4).

В рамках локальной переменной, введенной в локальной переменной-декларации, это ошибка во время компиляции, чтобы обратиться к , что локальная переменная в текстовом положении, которое предшествует его локальный_файл с переменной декларатор. Если объявление локальной переменной неявно (§8.5.1), также является ошибкой ссылаться на переменную в пределах ее local-variable-declarator.

+0

Да, хорошая референция. Он четко объясняет поведение (или правило) компилятора. Хотя это не объясняет, почему такое решение было принято. Я надеялся получить пример, где было бы очевидно, почему это правило существует. – Antonio

0

На самом деле ваш код должен быть точным, но по строгой интерпретации существует путь к коду, который может оставить ваши переменные неназначенными перед использованием.попробовать блок вводит потенциал для кода в блоке не будет выполнен (если исключение), но все-таки выполнить код за пределы улова (потому что нет ничего в уловом, такие как возвращения или throw, чтобы предотвратить выполнение остальной части вашего метода, если исключение выбрано в , попробуйте).

Если вы имеете в виду разницу между инициализацией «STRUCT» полей и инициализации класса полей, например:

public class A 
    { 
    } 

     MyMethod() 
     { 
      int myInt; // Initialized to zero, yes, but not yet assigned. 
         // An error to use this before assigning it. 

      A myA; // defaults to null, which may be a valid initial state, but still unassigned. 
        // Also an error to use this before assigning it. 

      A oneMoreA = null; // Same value as default, but at least intention is clear. 
      A anotherA = new A(); // What is or is not happening in the constructor is a separate issue. 
           // At least anotherA refers to an actual instance of the class. 
2

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

  1. Дайте вам диагностику, обращая ваше внимание на то, что может быть ошибкой.
  2. Сделайте что-нибудь произвольное.

Поскольку вариант # 1 помогает найти ошибки, предпочтительно, особенно когда обходной путь, чтобы сообщить компилятору «Нет, я имею в виду использовать исходное значение по умолчанию» так же просто, как добавление = 0, = null или = default(T).

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

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

Смежные вопросы