为什么C#局部变量应该直接赋值,即使它是默认值?

时间:2014-01-18 21:39:33

标签: c# compiler-construction initialization default-value local-variables

如果你看下一个例子:

public void TestLocalValuesAssignment()
{
    int valueVariable; // = default(int) suits fine
    string refType; // null suits fine as well

    try
    {
        valueVariable = 5;
        refType = "test";
    }
    catch (Exception){}

    Console.WriteLine("int value is {0}", valueVariable);
    Console.WriteLine("String is {0}", refType);
}

您可以很容易地看到,变量valueVariablerefType可以在Console.WriteLine()中使用之前取消分配。编译器告诉我们有错误:

Error   1   Use of unassigned local variable 'valueVariable'
Error   2   Use of unassigned local variable 'refType'  

这是一个普遍的案例,loads of answers如何解决这个问题(可能的修补程序已被评论)。

我无法理解的是为什么存在这种行为? 这里的局部变量如何与类字段不同,其中最后一个变量获得默认值(如果未分配)(参考类型为null,值类型为对应的默认值)?也许有一个例子或一个角落案例解释了为什么选择这样的编译器行为?

4 个答案:

答案 0 :(得分:12)

基本上 - 这就是MS的决定。

如果您需要更多内容,可以阅读here并查看Eric Lippert’s Blog

  

这在C#中是非法的原因是因为使用未分配的本地很可能是一个错误。

答案 1 :(得分:4)

在c#spec中描述:

  

5.1.7本地变量

     

local-variable-declaration 引入的局部变量不是   自动初始化,因此没有默认值。为了   明确赋值检查的目的,引入局部变量   通过 local-variable-declaration 被认为是最初未分配的。一个    local-variable-declaration 可能包含 local-variable-initializer ,   在这种情况下,变量被认为是仅明确分配的   在初始化表达式之后(第5.3.3.4节)。

     

在a引入的局部变量的范围内    local-variable-declaration ,它是一个引用的编译时错误   该局部变量位于其前面的文本位置   局部变量声明。如果是局部变量声明   隐式(第8.5.1节),引用其中的变量也是一个错误   它的 local-variable-declarator

答案 2 :(得分:2)

当你做一些出现愚蠢的事情时,比如读取你从未分配的变量,编译器基本上可以做两件事:

  1. 给你一个诊断,提醒你注意可能出现的错误。
  2. 做一些随意的事。
  3. 由于选项#1可以帮助您发现错误,因此首选,尤其是当告诉编译器“不,我的意思是使用原始默认值”的解决方法就像添加= 0一样简单,{{1 }或= null

    至于为什么类成员不以相同的方式工作,这是因为在编译时无法检查(因为可以调用不同方法的无数不同的命令)。无论是否已分配每个成员,都会有标记的运行时成本,以及对这些标志的测试。

    请注意,编译器确实以一种易于在编译时检查的方式强制执行对struct成员的限制。也就是说,每个构造函数都需要分配每个成员。

答案 3 :(得分:0)

实际上,您的代码应该没问题,但是通过严格的解释,有一个代码路径可以在使用前保留您的变量。 try 块引入了块中代码不能执行的可能性(如果抛出异常),但仍然执行 catch 之外的代码(因为没有任何内容)在 catch 中,例如返回抛出,以防止在尝试<中抛出异常时执行其余方法/强>)。

如果您指的是初始化“struct”字段和初始化类字段之间的区别,例如:

public class A
   {
   }

       MyMethod()
       {
           int myInt; // Initialized to zero, yes, but not yet assigned.
                      // An error to use this before assigning it.

           A myA;  // defaults to null, which may be a valid initial state, but still unassigned.
                   // Also an error to use this before assigning it.

           A oneMoreA = null; // Same value as default, but at least intention is clear.
           A anotherA = new A(); // What is or is not happening in the constructor is a separate issue.
                                 // At least anotherA  refers to an actual instance of the class.