为什么这个编译错误

时间:2012-01-11 17:04:30

标签: c# compilation

为什么我写

void Main()
{
      string value = @"C:\";
      if (!string.IsNullOrEmpty(value))  { 
            string sDirectory = Path.GetDirectoryName(value);
      }

}

它编译。<​​/ p>

如果我写的话

void Main()
{
      string value = @"C:\";
      if (!string.IsNullOrEmpty(value))
        string sDirectory = Path.GetDirectoryName(value);


}

不是吗?

很明显,从纯粹的功能角度来看, second 示例中变量的声明是无用的,但为什么神奇地第一<中变得有用/ em>例子,所以?

两个示例生成的IL代码完全相同。

IL_0000:  ldstr       "C:\"
IL_0005:  stloc.0     
IL_0006:  ldloc.0     
IL_0007:  call        System.String.IsNullOrEmpty
IL_000C:  brtrue.s    IL_0015
IL_000E:  ldloc.0     
IL_000F:  call        System.IO.Path.GetDirectoryName

编辑:

忘记为第二种情况生成IL代码(所以可编译的情况),这就足以在没有string sDirectory =的情况下编译

5 个答案:

答案 0 :(得分:20)

if语句的制作在C#规范的第8.7.1节中,它是这样的:

if-statement:
    if   ( boolean-expression )   embedded-statement
    if   ( boolean-expression )   embedded-statement   else   embedded-statement

C#规范第8节的开头在给出规范之后明确地讨论了 embedded-statement 生产:

embedded-statement:
   block
   empty-statement
   expression-statement
   selection-statement
   iteration-statement
   jump-statement
   try-statement
   checked-statement
   unchecked-statement
   lock-statement
   using-statement 
   yield-statement
     

嵌入式语句非终结符用于出现在其他语句中的语句。嵌入式语句而不是语句的使用排除了在这些上下文中使用声明语句和带标签的语句。例子

void F(bool b) {
     if (b)
         int i = 44;
} 
     

导致编译时错误,因为if语句需要嵌入语句而不是if分支的语句。如果允许此代码,那么将声明变量i,但它永远不会被使用。但是请注意,通过将i的声明放在一个块中,该示例是有效的。

请注意,赋值计为表达式语句 - 但本地变量声明不会。 (这是声明声明,如第8.5节所述。)

就设计决策而言,声明一个你不能使用的变量是没有意义的 - 因此编译器会阻止你这样做

答案 1 :(得分:6)

你的第二个表单试图使用有效的两个语句(一个变量声明和一个变量赋值),其中只能使用一个语句。把它想象成:

if (!string.IsNullOrEmpty(value))
    string sDirectory;
    sDirectory = Path.GetDirectoryName(value);

你可以看到这不会编译!

答案 2 :(得分:5)

带括号的第一个版本声明了一个新的局部作用域,在其中声明了一个字符串变量,第二个版本没有 - 变量声明和赋值被解释为一个嵌入式语句,可能不包含变量声明,因此编译错误。

答案 3 :(得分:1)

string value = @"C:\";
if (!string.IsNullOrEmpty(value))
string sDirectory = Path.GetDirectoryName(value);

第二个语句是被认为是嵌入语句的...如果你想在它周围的所谓的“代码块”包裹{}中使用sDirectory。在我看来,你想要做的内联陈述会导致可读性差。

 string value = @"C:\";
 string sDirectory = string.Empty; should be even better way to code..
 if (!string.IsNullOrEmpty(value))
 {
     sDirectory = Path.GetDirectoryName(value);
 } 

或者

现在两个案例都应该编译

  string value = @"C:\";
  string sDirectory = string.Empty;
  if (!string.IsNullOrEmpty(value))
     sDirectory = Path.GetDirectoryName(value);

答案 4 :(得分:1)

我不确定C#,但其他语言就是这种情况:因为{}打开一个块,因此打开一个新范围。如果省略它们,那么变量将在Main的范围内声明,因此只会在某些时候声明,因此编译器之后不知道sDirectory是否存在。