在.NET中初始化空变量

时间:2010-08-28 20:16:29

标签: c# .net variables initialization

在.NET中初始化null变量的正确方法是什么?我的一位同事告诉我,将变量硬定义为null是一种放缓。

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

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

这是对的吗?

9 个答案:

答案 0 :(得分:9)

假设您实际上是指默认值而不是 null 值,如果您实际分配,它可能会非常轻微地降低的速度构造函数中的值而不是变量声明中的值。如果它是变量声明的一部分,我会可能期望JIT编译器删除不必要的赋值,因为在第一次初始化时擦除了对象的内存。

然而,在任何一种情况下,这种重要性的可能性都非常小。

您认为哪种形式更易读?在绝大多数情况下, 更重要。

编辑:请注意,至少对于静态字段,存在两种行为方式不同的微妙情况。下面是一个示例 - 就y声明是否具有赋值而言,Test1和Test2类仅

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(); 
    }
}

答案 1 :(得分:3)

对于.net中的int,实际上无法为其分配null,因为它是值类型而非引用类型,除非您将其创建为int?Nullable<int>),虽然它是一个值类型,但它具有特殊的语义,因此可以为其分配null

在您的示例中,没有必要将0分配给var2,因为int的默认值为零。也就是说,如果c#编译器(尽管可能是编译器为两者生成不同的MSIL的情况),我会感到非常惊讶/ CLR解释器将两者都视为完全相同。

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

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

请记住,在这个最终毫无意义的函数中,对于尝试比较si都会出现编译错误,因为两者都是“未分配的本地人”。这与类的成员变量不同,如:

public class MyClass
{
    int i;

    public void MyFunction()
    {
        if (i == 1)
        {
        }
    }
}

答案 2 :(得分:1)

我不会说后者是一种不好的做法。它更明确,是C风格语言程序员中众所周知的习语。

答案 3 :(得分:1)

整数是值类型,因此无法初始化为null。

预初始化的性能损失可以忽略不计,但如果没有必要,应该避免。有关详细信息,请查看gain performance by not initializing variables的方法。另外,请查看Jeff Atwood的博文:For Best Results, Don't Initialize Variables.

答案 4 :(得分:1)

在C#中任何未初始化的变量使用都会生成编译器警告(如果至少有一个代码路径没有初始化)。在最终的代码中不应该有任何警告!

在第二个语句中,您指定了一个默认值。在第一个语句中,您假设所有代码路径都将为其分配一些值。

答案 5 :(得分:1)

如果没有指定其他显式值,您将需要将引用类型的局部变量初始化为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;

另一方面字段,例如“成员变量”在类级别,您不需要为这些值分配显式值。

另见:

答案 6 :(得分:1)

您不能将null分配给值类型,例如int。但是,在.NET的更高版本中,您可以使用可空值类型:

int? var1 = null;

在声明中初始化变量并不是一种坏习惯。事实上,情况正好相反。通过这样做,任何人都不会怀疑变量在声明之后的价值。

此外,将null分配给您不必担心的变量会产生如此微小的性能损失。专注于编程以获得准确的功能;一旦你有了这个,然后调整可能出现的任何明显的性能问题。

答案 7 :(得分:1)

如果您正在讨论成员变量,可能还有另一个原因是不能使用默认值初始化它们:符合规则CA1805: DoNotInitializeUnnecessarily的FxCop。

如果其中一个要求是编写符合FxCop的代码,则无法使用默认值初始化变量。

答案 8 :(得分:1)

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机器。开销可能大约是半纳秒左右。不是容易衡量的东西。