null和未初始化之间的区别是什么?

11

当我在C#中编写以下代码时:

SqlCeCommand command;
try
{
    // The command used to affect the data
    command = new SqlCeCommand
                  { 
                     // init code removed for brevity
                  };

    // Do stuff 
    // Do more stuff
}
finally
{
    if (command != null)
        command.Dispose();
}

Resharper提示我检查command != null,它说command可能未被赋值(因为在构造过程中可能会失败并仍然命中try块)。

于是我将command的声明更改为SqlCeCommand command = null;,这样大家都很开心。

但我想知道这样做有什么区别?

为什么C#不直接默认将局部变量设置为null呢?意思是: C#从不将局部变量默认设置为null对其有何益处?


因为C++似乎是唯一“真正”的答案。 - Vaccano
6个回答

8

本地变量没有默认值。这是语言的一部分。


3
为什么?为什么不将它们默认设置为 null 呢?要求赋值有什么好处? - Vaccano
就像mrz所说的那样——它是为了保护程序员。其他语言(如Java)也存在同样的规则。我曾经因为编译器发现可能导致在分配明确值之前使用本地变量的执行路径而受到这个规则的保护。结果证明,这几乎总是由于我的错误造成的。如果本地变量有默认值,这种检查将是不可能的。(顺便说一下,为什么要对正确的答案进行负面评价?如果你不喜欢信息,为什么要伤害信息的传递者呢?) - Ted Hopp
我在这个问题上没有投下反对票(通常很少投反对票)。仅仅因为一个stackoverflow回答不是我想要的,我不会投反对票。 - Vaccano
@Vaccano - 对不起。似乎有人对你提出异议的每个答案进行了投票。我错误地认为这是你的投票。 - Ted Hopp

5
如果你希望它为空,那么你需要明确地说明。这是为了捕获错误。编译器和像ReSharper这样的工具搜索所有执行路径,并确保在使用之前初始化变量。这是为了捕获常见的编码错误。因此,没有额外的“不甚至为null”的可能值,这只是编译器(或任何其他工具)执行的分析,以帮助你解决问题。
类成员被初始化为默认值(例如,引用类型为null),因此你可以得到你所期望的行为。

我认为这也是一种优化。在将某个变量设置为另一个值之前将其赋值为null只会浪费指令。 - Mark H
如果编译器不是太差的话,它应该会检测到这一点,甚至不会执行初始赋值。 - Anders Zommarin

3

这与C#旨在帮助确保代码正确性有关。在类声明中(而不是在局部变量中),成员具有隐式值,因此您无需在声明或类构造函数中显式设置它们。但是,在函数/方法的上下文中,C#会跟踪变量是否已被显式设置,以便可以警告您像您所看到的那样的事情……这是语言设计决策。


1
嗯,似乎在类级别上要求初始化和在本地级别上一样容易。如果在本地级别上是“好的”,为什么在类级别上不是呢? - Vaccano
我同意。有趣的是,http://msdn.microsoft.com/en-us/library/aa691172(v=VS.71).aspx说结构体的成员共享“明确赋值跟踪”行为,但没有提到类。 - JaredReisinger
啊...前面的章节,http://msdn.microsoft.com/en-us/library/aa691171(v=VS.71).aspx,提到静态变量和类实例变量会获得默认值。但是没有解释这个现象的原因。 - JaredReisinger

1

您可以使用using结构编写等效但更紧凑的代码,它会为您调用Dispose

using (var command = new SqlCeCommand
       { 
           // init code removed for brevity
       })
{

    // Do stuff 
    // Do more stuff
}

您无需担心释放资源或检查空值。


0

类成员字段会被默认初始化(值类型根据其类型,引用类型为null),但局部变量不会。

// Example 1:
SomeClass someObject;
if(x == y)
{
    someObject = new SomeClass();
}
someObject.someMethod();   //Error since it may not execute the if statements

// Example 2
SomeClass someObject;
someObject = new SomeClass();
someObject.someMethod();   //No Error

编辑:这是为了避免C++运行时错误,导致程序意外关闭(因为空指针)。

P.S:当我谈论C#规范时,您可能不会对我进行负面评价(我没有制定C#规范,但我支持这种避免方法)。


但是为什么呢?为什么不要求两者都初始化或都不初始化呢? - Vaccano
我没有进行踩票!(而且我刚刚点了赞)事实上,你的C++参考资料是我听过的最好的真正原因(尽管我不太明白为什么在C#中C++的行为很重要,除非这只是一种惯例)。 - Vaccano
@Vaccano 我曾经在某处读到过 C# => C++++,我知道它与其他编程语言有很大的区别,也更加强大,但是它可以成为抛弃旧编程语言以追求最新技术的良好路线图。 - Ken D

0

你可以测试 null,因为 null 是一个值。 未初始化意味着没有值,所以你不能对其进行测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接