我熟悉C#规范,第 5.3 节指出在使用变量之前必须对其进行赋值。
在 C 和非托管 C++ 中,这是有道理的,因为堆栈不会被清除,用于指针的内存位置可以是任何地方(导致难以跟踪的错误)。
但我认为运行时不允许真正“未分配”的值。特别是,未初始化的引用类型将始终具有 null 值,而不是上一次调用该方法留下的值或随机值。
这是正确的吗?多年来,我一直错误地认为检查 null 就足够了吗?在 C# 中,您是否可以拥有真正未初始化的变量,还是 CLR 会处理这个问题,总是有一些值被设置?
在使用本地变量之前必须明确赋值的规则,其原因并不是为了防止您观察本地变量未初始化的垃圾状态。这已经无法观察到,因为CLR会将本地变量积极清除为默认值,就像它对字段和数组元素所做的那样。之所以在C#中这样做是不合法的,是因为使用未赋值的本地变量具有很高的可能性成为错误。我们只是使其非法化,然后编译器会防止您出现此类错误。
http://msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx
这份文档指出以下内容都会自动分配默认值。http://msdn.microsoft.com/en-us/library/aa691173(v=vs.71).aspx
关于实际默认值的更多信息请参见: C#类型的默认值(C#参考)
这取决于变量声明的位置。在类中声明的变量会使用默认值自动初始化。
object o;
void Method()
{
if (o == null)
{
// This will execute
}
}
在一个方法中声明的变量未被初始化,但当这个变量第一次被使用时,编译器会检查是否已经初始化,因此代码将无法编译。
void Method()
{
object o;
if (o == null) // Compile error on this line
{
}
}
有三种方法可以给变量赋初始值:
默认情况--如果您声明一个类变量而没有分配初始值,则会发生这种情况,因此初始值得到的是default(type)
,其中type
是您声明变量的任何类型。
使用初始化器--当您声明具有初始值的变量时,例如int i = 12;
。
在检索其值之前的任何时间点--如果您有一个没有初始值的局部变量,则会发生这种情况。编译器确保您没有可达的代码路径将在分配变量值之前读取变量的值。
在任何时候,编译器都不允许您读取未初始化的变量的值,因此您永远不必担心尝试读取未初始化变量时会发生什么。
所有原始数据类型都有默认值,因此不需要担心它们。
所有引用类型都初始化为null值,因此如果您将引用类型未初始化,然后调用该null引用类型的某些方法或属性,则会出现运行时异常,需要优雅地处理。
同样,如果未初始化所有可空类型,则需要检查其是否为null或默认值,如下所示:
int? num = null;
if (num.HasValue == true)
{
System.Console.WriteLine("num = " + num.Value);
}
else
{
System.Console.WriteLine("num = Null");
}
//y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try
{
y = num.Value;
}
catch (System.InvalidOperationException e)
{
System.Console.WriteLine(e.Message);
}
但是,如果您将所有变量未初始化,则不会收到任何编译错误,因为编译器不会抱怨。只有运行时需要担心。
out
调用必须将值设置为某些内容,除非它抛出异常。这个规则严格来说是浪费的——如果我们收到false,那么我们不应该使用这个值——但是它消除了否则存在的脆弱性。 - Jon Hannaout
的情况不同,因为你不需要在返回 true 或 false 的函数中使用它。它是糖,但不是浪费,它对于确保所有代码路径都设置了一个值非常有用。如果你不想要它,你就不会使用它。 - jmoreno