为什么这个编译错误

Tig*_*ran 9 c# compilation

为什么我写

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

}
Run Code Online (Sandbox Code Playgroud)

它汇编.

如果我写的话

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


}
Run Code Online (Sandbox Code Playgroud)

不是吗?

很明显,从纯粹的功能观点来看,第二个例子中变量的声明是无用的,但为什么它在第一个例子中神奇地变得有用,所以呢?

两个示例生成的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
Run Code Online (Sandbox Code Playgroud)

编辑:

忘了IL为第二种情况生成代码(所以不能编译的情况),这就足够了string sDirectory =

Jon*_*eet 20

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

if-statement:
    if   ( boolean-expression )   embedded-statement
    if   ( boolean-expression )   embedded-statement   else   embedded-statement
Run Code Online (Sandbox Code Playgroud)

C#规范第8节的开头在给出规范之后明确地讨论了嵌入式语句的产生:

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
Run Code Online (Sandbox Code Playgroud)

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

void F(bool b) {
     if (b)
         int i = 44;
} 
Run Code Online (Sandbox Code Playgroud)

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

请注意,赋值计为表达式语句 - 但局部变量声明不计算.(这是一份声明声明,如第8.5节所述.)

就设计决策而言,声明一个你不能使用的变量是没有意义的 - 所以编译器阻止你做这件事是好的.

  • 实际上,对于规范来说,变量可能*永远不会被使用,实际上并非*相当正确.`if(x)int i = M(out i)+ i;`会写和读`i`; 这样的局部变量声明非常奇怪,但是合法的.真正应该说准确的是,由初始化器*的值确定的i*的值永远不能被使用. (5认同)

Dav*_*d M 6

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

if (!string.IsNullOrEmpty(value))
    string sDirectory;
    sDirectory = Path.GetDirectoryName(value);
Run Code Online (Sandbox Code Playgroud)

你可以看到这不会编译!


Bro*_*ass 5

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