无法在条件语句中声明局部变量

时间:2010-02-11 18:56:56

标签: c# .net

这是允许的:

        // scope_1
        int i = 100;
        if (i > 50)
        {
            // scope_2
            int a = 200;
        }

这会出错:

        // scope_1
        if (100 > 50)
            int a = 200;

第二个代码示例的原因是否由于范围而导致错误?因此编译器不允许在条件语句求值为true时声明特定作用域内的变量 a ,因为如果它确实允许,那么编译器就无法确定是否允许在scope_1中声明另一个名为 a 的变量?

9 个答案:

答案 0 :(得分:13)

if (100 > 50)
    int a = 200;

你为什么要这样做?在声明为变量的单语句范围内声明变量似乎没有意义,因为您实际上没有时间使用声明的变量。

如果允许您在a语句之外引用if,则上述操作将导致条件变量声明。但是,声明不能是有条件的。编译器在遇到可以声明或未声明的标识符时可以合理地做些什么?无论哪种情况都只能在运行时计算出来,而不是在编译时;但编译器需要知道(因为未声明的标识符是语法错误),因此它会抱怨这个结构。

答案 1 :(得分:8)

您在if语句中没有使用括号,因此此后只允许使用一个语句。如果变量无法被引用,那么对变量进行尺寸标注有什么意义呢?

此外,您的第二个if语句使用文字常量,显然永远不会成立。再说一次,将任何内容放入其中是什么意思?

也许我误解了你的问题。

答案 2 :(得分:5)

让我稍微改一下你的问题。

  

规范的哪个部分定义了这种行为?

第8.7.1节规定“if”的陈述是“嵌入式陈述”。

第8节的开头指出嵌入语句可以是块或空,表达式,选择,迭代,跳转,尝试,检查,取消选中,锁定,使用或屈服语句,但不是带标签的语句或声明言。

  

为什么不允许声明声明?

原始语言笔记没有涉及这个特定点,但我们可以做一些有根据的猜测。你的猜想很好;这样做会使得很难推断所声明的本地范围。如果我们允许它,那么我们必须决定“if”是否隐式地创建一个局部变量声明范围,即使没有块:

if (x) int y = M();
else string y = N();

这是重新声明的本地变量错误吗?或条件的每个分支是否产生自己的局部变量声明空间?

这个怎么样?

if(x) int y = M();
else y = N();
Q(y);

y是否在范围之外?如果是这样,它是否在到达Q(y)时被明确分配?

我对这里正确的事情没有强烈的直觉。无论我们选择哪一个,似乎有一半的人会认为我们选错了。如果你想引入一个新的局部变量声明空间,那么更好的做法是使整个认为非法并需要括号。

现在有些问题没有问:

  

开关块怎么样?是否适用相同的规则?

没有。阅读本文:

http://ericlippert.com/2009/08/13/four-switch-oddities/

  

如果我合法地声明一个局部变量但只分配给它,会发生什么情况,就像我在带有条件的结果中的块的例子一样?

有时你会收到警告。有时候你没有。

  

编译器如何决定是否发出警告?

阅读本文:

http://blogs.msdn.com/ericlippert/archive/2007/04/23/write-only-variables-considered-harmful-or-beneficial.aspx

答案 3 :(得分:3)

看看你的第二个案例:

if (100 > 50)
    int a = 200;

您声明的变量“a”只能在该单个语句中使用。但是,它是一个l值,因此定义变量的整个目的是稍后使用它。

你做不到(出于显而易见的原因):

if (100 > 50)
    int a = 200;

Console.WriteLine(a); // This makes no sense... What happens if 100 < 50????

编译器足够聪明,在这种情况下会出错,因为如果允许的话,你真的无法使用该变量。

答案 4 :(得分:2)

因为您无法访问{}的访问权限。如果编译器允许你这样做,变量的范围

  

仅限于大括号。

        // scope_1
        int i = 100;
        if (i > 50)
        {
            // scope_2
            int a = 200;
        }

        // if you will try
        int anotherA = a; // a does not exist in the current context

答案 5 :(得分:2)

看看

Statements

  

if不是强制性的   声明如果我们想要{}   将其范围限制为只有一行。   但是,我们不能有变量   声明作为以下唯一的一行   它。这是因为如果条件   结果为假,变量会   永远不会被创造。

另外看看

Statements (C# Programming Guide)

  

不是的嵌入式语句   括在{}括号内不能是一个   声明或声明   言。

答案 6 :(得分:1)

创建第二个范围只包含一条指令,因此声明一个变量(已经是一条指令)是没用的,因为它只能在该范围内使用。

编译器永远不会错!

答案 7 :(得分:1)

这与编辑器智能与“范围”无关,a是否在if之外可见。

C89标准不允许任何一种构造。在C99中,您可以在块的开头(复合语句)声明一个变量,而不是其他地方。

此代码没有块:

 if ( i )
   int a = 100;

它也没有隐含的阻止 - 这可能就是你在想的。 “if”后面可以跟一个语句或复合语句。复合语句是允许您拥有声明列表的地方。上面的内容只是一个声明。

您可以通过添加{}来将其转换为复合语句。

if ( 表达 ) 声明

其中语句可以是单个语句,也可以是复合语句

复合语句:    { 声明列表 声明列表}

(另见K&amp; R 2ed A9.3“化合物声明”)

如上所述,这是一个C#问题。 C#标准在第15.2节中对此进行了讨论,但并不简洁。 :)基本上,声明需要一个块。块需要括号。故事结束。

答案 8 :(得分:1)

您得到的错误是:

error CS1023: Embedded statement cannot be a declaration or labeled statement

这意味着 if-statement 的语法需要条件表达式后面的语句语句块

if-stmt -> 'if' '(' expr ')' stmt ['else' stmt]  

stmt ->    if-stmt
     ->    do-stmt
     ->    ...etc...
     ->    '{' [declaration...] [stmt...] '}'

声明不是声明,因此这是一个简单的语法错误。