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

Являются ли неинициализированные переменные С# опасными?

Я знаком с спецификацией С#, в разделе 5.3, в которой говорится, что перед использованием должна быть назначена переменная.

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

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

Это правильно, или я ошибочно полагал, что проверка на нуль достаточна все эти годы? Можете ли вы иметь неинтеллизированные переменные в С#, или CLR позаботится об этом, и всегда будет установлено НЕКОТОРНОЕ значение.

4b9b3361

Ответ 1

У меня создается впечатление, что во время выполнения нет действительно "неназначенных" значений. В частности, что ссылочный тип, который не инициализирован, всегда будет иметь нулевое значение, а не значение, оставшееся от предыдущего вызова метода или случайного значения. Правильно ли это?

Замечу, что пока никто не ответил на ваш вопрос.

Ответ на заданный вами вопрос - "sorta".

Как отмечали другие, некоторые переменные (элементы массива, поля и т.д.) классифицируются как автоматически "первоначально назначенные" для их значения по умолчанию. (Который является нулевым для ссылочных типов, нолем для числовых типов, false для bools и естественной рекурсией для определяемых пользователем структур).

Некоторые переменные не классифицируются как первоначально назначенные; локальные переменные, в частности, изначально не назначаются. Они должны быть классифицированы компилятором как "определенно назначенные" во всех точках, где используются их значения.

В действительности ваш вопрос - это локальная переменная, которая классифицируется как не определенно назначенная, фактически первоначально назначенная так же, как поле было бы? " И ответ на этот вопрос да, на практике среда выполнения сначала назначает всех локальных пользователей.

У этого есть несколько приятных свойств. Во-первых, вы можете наблюдать их в отладчике, чтобы они находились в состоянии по умолчанию перед их первым назначением. Во-вторых, нет никаких шансов, что сборщик мусора будет обманут в разыменование плохого указателя только потому, что в стеке остался мусор, который теперь рассматривается как управляемая ссылка. И так далее.

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

Причина того, что правило о том, что локальные жители должны быть обязательно назначены до их использования, не должно препятствовать вам наблюдать неинициализированное состояние мусора локального. Это уже ненаблюдаемо, потому что среда CLR агрессивно очищает локали до значений по умолчанию, так же как и для полей и элементов массива. Причина, по которой это незаконно в С#, состоит в том, что использование неназначенного локального сервера имеет большую вероятность быть ошибкой. Мы просто делаем это незаконным, а затем компилятор не позволяет вам когда-либо иметь такую ​​ошибку.

Ответ 2

Насколько мне известно, каждый тип имеет заданное значение по умолчанию.

В соответствии с этим документом полям классов присваивается значение по умолчанию.

http://msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx

В этом документе указано, что следующие значения всегда присваиваются автоматически.

  • Статические переменные.
  • Переменные экземпляра экземпляров класса.
  • Переменные экземпляра изначально назначенных переменных структуры.
  • Элементы массива.
  • Значения параметров.
  • Справочные параметры.
  • Переменные, объявленные в предложении catch или foreach.

http://msdn.microsoft.com/en-us/library/aa691173(v=vs.71).aspx

Дополнительная информация о фактических значениях по умолчанию здесь: http://msdn.microsoft.com/en-us/library/83fhsxwc.aspx

Ответ 3

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

Я думаю, вы смешиваете локальные переменные и переменные-члены. В разделе 5.3 конкретно говорится о локальных переменных. В отличие от переменных-членов, которые получают дефолт, локальные значения по умолчанию не равны нулю или что-то еще: они просто должны быть назначены до их первого чтения. В разделе 5.3 описаны правила, используемые компилятором для определения того, была ли назначена локальная переменная.

Ответ 4

Это зависит от того, где объявлена ​​переменная. Переменные, объявленные в классе, автоматически инициализируются с использованием значения по умолчанию.

object o;
void Method()
{
    if (o == null)
    {
        // this will execute
    }
}

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

void Method()
{
    object o;
    if (o == null) // compile error on this line
    {
    }
}

Ответ 5

Существует 3 способа присвоения переменной переменной:

  • По умолчанию - это происходит (например), если вы объявляете переменную класса без назначения начального значения, поэтому начальное значение получает default(type), где type - это любой тип, который вы объявляете переменной.

  • С инициализатором - это происходит, когда вы объявляете переменную с начальным значением, как в int i = 12;

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

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

Ответ 6

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

Все ссылочные типы инициализируются нулевыми значениями, поэтому, если вы оставите свои ссылочные типы неинициализированными, а затем вызовите какой-либо метод или свойство в этом типе null ref, вы получите исключение во время выполнения, которое необходимо обработать изящно.

Опять же, все типы Nullable должны быть проверены на значение null или по умолчанию, если они не инициализированы следующим образом:

    int? num = null;
    if (num.HasValue == true)
    {
        System.Console.WriteLine("num = " + num.Value);
    }
    else
    {
        System.Console.WriteLine("num = Null");
    }

    //y is set to zero
    int y = num.GetValueOrDefault();

    // num.Value throws an InvalidOperationException if num.HasValue is false
    try
    {
        y = num.Value;
    }
    catch (System.InvalidOperationException e)
    {
        System.Console.WriteLine(e.Message);
    }

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