为什么未自动初始化未分配的局部变量?

似乎没有办法在代码中使用未分配的局部变量或检查它们,因为编译器吐出Use of unassigned local variable错误。

为什么编译器在编译时不对这些变量使用default(T)

即使对值类型更难做,在这种情况下,引用类型也可以很容易地初始化为null ,对吧?

这是一些测试代码:

 public void Test ( ) { int x; string s; if ( x == 5 ) Console.WriteLine ( 5 ); if ( s != null ) Console.WriteLine ( "s" ); } 

返回:

 Use of unassigned local variable 'x' Use of unassigned local variable 's' 

更新:

对于声称这是不允许有充分理由的人,为什么允许在课堂级别?

 public class C { public int X; public string S; public void Print ( ) { Console.WriteLine ( X ); Console.WriteLine ( S ); } } 

这段代码编译得很好。

为什么在类级别而不是在方法级别上没有问题?

我看到你已经更新了你的问题,所以我会更新我的答案。 您的问题有两个部分,一个与local variables相关,另一个与instance variables on a class instance 。 然而,首先,这不是一个真正的编译器设计决策,而是一个语言设计决策。

规范第12.3.1 / 12.3.2节

局部变量

我们知道为什么你可以定义一个变量而不给它一个值。 一个原因,这样的例子:

 int x; // do stuff x = 5; // Wow, I can initialize it later! Console.WriteLine(x); 

该标准定义了这是有效代码的原因。 现在,我不是在C#设计团队,但很有道理他们不会为你自动初始化代码(除了你实际上希望它自动初始化时的性能影响)。

说上面的代码是你的意图,但你忘了初始化x = 5; 。 如果编译器已经为你自动初始化了变量,那么代码就会编译,但是它会像你期望的那样做。

虽然这是一个微不足道的例子,但这是一个非常好的语言设计师的设计决定,因为它可以避免许多令人头疼的问题,试图弄清楚为什么某些东西没有按预期工作。

作为旁注,我想不出你为什么要在没有赋予它的情况下定义代码的原因,或者使用默认值(在每种情况下),对我来说可能是一个bug,我就是确定编译器设计者可能已经确定了什么。

类实例变量

类级别成员由最初分配的标准定义。 实际上,公平地说,在catchforeachusing语句中声明的局部变量最初是未分配的。 实际上,这是一个标准问题,而不是编译器问题。

如果我试图猜测为什么这是关于类实例的实例变量的情况,我会说它与如何在堆上分配内存有关,因为那是分配类的地方。 在堆上分配类时,必须初始化其所有成员并在堆上分配它。 在类成员而不是局部变量中执行它不仅可以,它必须以这种方式完成。 它们根本不能被取消分配。

C#是一个“成功的坑”语言。

这是一个设计决策,因为该语言完全能够允许您使用未明确分配的本地。 但是,通常情况下,这些变量的使用是错误的,代码路径由于某种原因没有设置值。 为避免此类错误,编译器要求在使用之前分配所有本地。

1为什么编译器不允许使用未初始化的变量?

因为防止促进良好的编程。

2为什么编译器允许使用未初始化的类成员?

因为无法准确跟踪这一点。

通过将您的建议初始化引用类型设置为null,而不是当前行为(错误代码导致编译时错误),当您取消引用未初始化的变量时,您将获得运行时错误。 这真的是你想要的吗?

请考虑以下代码:

 void blah(IDictionary dict) { for (int i=0; i<10; i++) { if ((i & 11) != 0) { int j; dict.TryGetValue(i, out j); System.Diagnostics.Debug.Print("{0}",j); j++; } } } 

假设IDictionary的传入实现的TryGetValue方法从未实际写入j [如果用C#编写,则不可能,但如果用另一种语言编写则可能]。 应该期望代码打印什么?

C#标准中没有任何内容要求在代码离开if语句时保持j ,但没有任何要求在循环迭代之间将其重置为零。 在某些情况下,强制采取任何行动都会产生额外费用。 标准只是允许在调用TryGetValue时, j可以任意保持零或它在范围内时保持的最后一个值,而不是两者之一。 这种方法避免了不必要的成本,但如果允许代码在重新进入作用域的时间和写入时间之间看到j的值(将未初始化的变量作为out参数传递给写入的代码),则会很麻烦在另一种语言中将暴露其价值可能是无意的)。

因为那里你想要什么? 你希望x默认为零,我希望它是5 …

如果他们将0分配给int(s)并且所有世界都开始假设,那么它们将在某个时刻变为-1,这将破坏全球许多应用程序。

在VB6中,我认为默认情况下会将变量分配给某个东西,并且它看起来并不像它看起来那么好。

当您使用C#或C ++时,您可以根据需要分配值,而不是为您编译。