Инициализация пустых переменных в .NET

What is the proper way to initialize a null variable in .NET? I've been told by one of my colleagues that hard defining of a variable to null is a slowdown.

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

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

Is that correct?

7
задан Greg B 28 August 2010 в 21:02
поделиться

9 ответов

Если вы на самом деле имеете в виду значение по умолчанию вместо 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(); 
    }
}
9
ответ дан 6 December 2019 в 09:57
поделиться

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

В вашем примере нет смысла присваивать 0 переменной var2, поскольку значение по умолчанию для int равно нулю. Тем не менее, я был бы очень удивлен, если бы компилятор С# (хотя может быть и так, что компилятор создает разные MSIL для двух)/интерпретатор CLR рассматривает оба как абсолютно одинаковые.

private void MyFunction()
{
    int i;
    string s;

    if (s == "3")
    {
        if (i == 1)
        {
        }
    }
}

Имейте в виду, что в этой совершенно бессмысленной функции вы получите ошибку компиляции как при попытке сравнить s, так и i, поскольку оба являются «неназначенными локальными переменными». . Это отличается от переменных-членов класса, например:

public class MyClass
{
    int i;

    public void MyFunction()
    {
        if (i == 1)
        {
        }
    }
}
3
ответ дан 6 December 2019 в 09:57
поделиться

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

1
ответ дан 6 December 2019 в 09:57
поделиться

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

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

1
ответ дан 6 December 2019 в 09:57
поделиться

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

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

1
ответ дан 6 December 2019 в 09:57
поделиться

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

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

1
ответ дан 6 December 2019 в 09:57
поделиться

Вы захотите инициализировать локальные переменные ссылочного типа в 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;

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

См. также:

1
ответ дан 6 December 2019 в 09:57
поделиться

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

int? var1 = null;

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

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

1
ответ дан 6 December 2019 в 09:57
поделиться

Среда 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 обычно неплохо справляется с оптимизацией бесполезного кода, но в данном конкретном случае он неуклюж.

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

1
ответ дан 6 December 2019 в 09:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: