在.NET中初始化空变量

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

int var1; // good practice string s1; // good practice int var2 = 0; // bad practice string s2 = null; // bad practice 

那是对的吗?

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

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

你觉得哪种forms更易读? 在绝大多数情况下,这一点更为重要。

编辑:请注意,至少对于静态字段,有一些细微的情况,两者的行为方式不同。 这是一个例子 – 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(); } } 

对于.net中的int ,实际上不可能为它赋值null ,因为它是值类型而不是引用类型,除非你将它创建为int?Nullable ),虽然它是一个值类型,但它具有特殊的语义,因此可以为其分配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) { } } } 

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

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

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

如果没有指定其他显式值,您将需要将引用类型的局部变量初始化为null,否则您将遇到“未初始化的局部变量”编译错误。 例:

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

其他类型的局部变量(参考和值类型)也是如此。 在您的示例中,它使用值类型,并且应声明局部变量:

 int var1 = 0; 

参考类型的相同forms是:

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

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

也可以看看:

  • 成员变量和局部变量之间有什么区别?
  • C#概念:值与参考类型

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

 int? var1 = null; 

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

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

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

预初始化的性能损失可以忽略不计,但如果没有必要,则应该避免。 有关详细信息,请查看如何通过不初始化变量来获得性能 。 另外,请查看Jeff Atwood的博客文章: 为了获得最佳结果,请不要初始化变量。

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

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

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