Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this compile error

Tags:

c#

compilation

Why if I write

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

}

it compiles.

And in case if I write

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


}

It doesn't ?

It's clear that from pure functional point of view the declaration of the variable in the second example is useless, but why it magically becomes usefull in first example, so ?

The IL code produced by both examples is exactly the same.

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

EDIT:

Forgot to mantion that to produce the IL code for the second case (so the case which is not compilable), it's enough to compile without string sDirectory =

like image 837
Tigran Avatar asked Jan 11 '12 17:01

Tigran


2 Answers

The production for an if statement is in section 8.7.1 of the C# spec, and it goes like this:

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

The start of section 8 of the C# spec explicitly talks about the embedded-statement production after giving the specification for it:

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

The embedded-statement nonterminal is used for statements that appear within other statements. The use of embedded-statement rather than statement excludes the use of declaration statements and labeled statements in these contexts. The example

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

results in a compile-time error because an if statement requires an embedded-statement rather than a statement for its if branch. If this code were permitted, then the variable i would be declared, but it could never be used. Note, however, that by placing i’s declaration in a block, the example is valid.

Note that an assignment counts as an expression-statement - but a local variable declaration doesn't. (That's a declaration-statement, as in section 8.5.)

In terms of a design decision, it makes no sense to declare a variable that you can't then use - so it's good that the compiler stops you from doing it.

like image 92
Jon Skeet Avatar answered Sep 17 '22 17:09

Jon Skeet


Your second form tries to use what is effectively two statements (a variable declaration and a variable assignment) where only a single statement could be used. Think of it as:

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

You can see this won't compile!

like image 28
David M Avatar answered Sep 21 '22 17:09

David M