Инициализация пустых переменных в .NET - PullRequest
7 голосов
/ 29 августа 2010

Как правильно инициализировать нулевую переменную в .NET? Один из моих коллег сказал мне, что жесткое определение переменной в ноль - это замедление.

int var1;          // good practice
string s1;         // good practice

int var2 = 0;      // bad practice
string s2 = null;  // bad practice

Это правильно?

Ответы [ 9 ]

9 голосов
/ 29 августа 2010

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

Тем не менее, шансы на то, что это существенно, в обоих случаях абсолютно крошечные.

Какую форму вы находите более читабельной? Это намного более важно в подавляющем большинстве случаев.

РЕДАКТИРОВАТЬ: Обратите внимание, что по крайней мере для статических полей, есть тонкие случаи, когда два не ведут себя одинаково. Вот пример - классы Test1 и Test2 отличаются только тем, имеет ли объявление y присваивание:

using System;

class Test1
{
    static int x = GetX();
    static int y = 0;

    public static void Hello()
    {
        Console.WriteLine("{0} {1}", x, y);
    }

    static int GetX()
    {
        y = 2;
        return 5;
    }
}

class Test2
{
    static int x = GetX();
    static int y;

    public static void Hello()
    {
        Console.WriteLine("{0} {1}", x, y);
    }

    static int GetX()
    {
        y = 2;
        return 5;
    }
}

class Test
{
    static void Main()
    {
        Test1.Hello();
        Test2.Hello(); 
    }
}
3 голосов
/ 29 августа 2010

Для int в .net фактически невозможно присвоить ему null, поскольку это тип значения, а не ссылочный тип, если вы не создадите его как int? (Nullable<int>),который является типом значения, имеет особую семантику и поэтому может иметь null.

В вашем примере нет смысла присваивать 0 для var2, поскольку значение по умолчанию для int равно нулю.Тем не менее, я был бы весьма удивлен, если бы компилятор c # (хотя это может быть тот случай, когда компилятор выдает разные MSIL для двух) интерпретатор / CLR рассматривает оба компонента как абсолютно одинаковые.Имейте в виду, что в этой, в конечном счете, бессмысленной функции вы получите ошибку компиляции для обеих попыток сравнить s и i, поскольку оба являются "неназначенными локальными пользователями".Это отличается от переменных-членов класса, например:

public class MyClass
{
    int i;

    public void MyFunction()
    {
        if (i == 1)
        {
        }
    }
}
1 голос
/ 29 августа 2010

CLR дает твердое обещание, что все локальные переменные будут инициализированы до значения по умолчанию при входе в метод перед выполнением первого оператора. Это обещание реализуется компилятором JIT. Понять это немного сложно, поскольку C # требует, чтобы переменные были явно инициализированы перед их использованием. Но вот пример:

    static void Main(string[] args) {
        int ix;
        int.TryParse("42", out ix);
        Console.WriteLine("", ix);
    }

Используйте Debug + Windows + Disassembly, чтобы увидеть сгенерированный код:

// Stack frame setup elided...
00000006  xor         eax,eax                        ; eax = 0
00000008  mov         dword ptr [ebp-0Ch],eax        ; ix = 0
// etc..

Перезапись этого кода для инициализации ix на ноль приводит к следующему коду:

00000006  xor         eax,eax                        ; eax = 0
00000008  mov         dword ptr [ebp-0Ch],eax        ; ix = 0
0000000b  xor         edx,edx                        ; edx = 0
0000000d  mov         dword ptr [ebp-0Ch],edx        ; ix = 0

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

Итак, ты друг прав. По крайней мере, для JIT-компилятора x86, сейчас не близко к машине x64. Накладные расходы, вероятно, около половины наносекунды или около того. Не то, что легко измерить.

1 голос
/ 29 августа 2010

Если вы говорите о переменных-членах, возможно, есть еще одна причина не инициализировать их значениями по умолчанию: соответствие FxCop правилу CA1805: DoNotInitializeUnnecessarily.

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

1 голос
/ 29 августа 2010

Нельзя присвоить значение null для типа значения, такого как int.Однако в более поздних версиях .NET вы можете использовать типы значений, допускающие значение NULL:

int? var1 = null;

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

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

1 голос
/ 29 августа 2010

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

Err

// Inside a method, property or indexer.
Random r; // compile error - Uninitialized local var

То же самое касается других типов локальных переменных, как ссылочных, так и типов значений. В вашем примере он использует тип значения, и локальная переменная должна быть объявлена:

int var1 = 0;

Такая же хорошая форма для ссылочных типов:

// Inside a method, property or indexer.
Random r = null;

С другой стороны Поля например «переменные-члены» находятся на уровне класса, вам не нужно присваивать им явное значение.

Смотри также:

1 голос
/ 29 августа 2010

При любом неинициализированном использовании переменной в C # генерируется предупреждение компилятора (если существует хотя бы один путь кода, инициализация не выполняется). И в вашем окончательном коде не должно быть предупреждений!

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

1 голос
/ 29 августа 2010

Целое число является типом значения, поэтому его нельзя инициализировать нулем.

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

1 голос
/ 29 августа 2010

Я бы не сказал, что последнее - плохая практика. Это более явная и известная идиома среди программистов языков C-стиля

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...