为什么 C # 允许{}没有前面的语句的代码块?

为什么 C # 允许没有前面语句的代码块(例如 ifelseforwhile) ?

void Main()
{
{   // any sense in this?
Console.Write("foo");
}
}
10008 次浏览

In the context you give, there is no significance. Writing a constant string to the console is going to work the same way anywhere in program flow.1

Instead, you typically use them to restrict the scope of some local variables. This is further elaborated here and here. Look at João Angelo’s answer and Chris Wallis’s answer for brief examples. I believe the same applies to some other languages with C-style syntax as well, not that they’d be relevant to this question though.


1 Unless, of course, you decide to try to be funny and create your own Console class, with a Write() method that does something entirely unexpected.

The { ... } has at least the side-effect of introducing a new scope for local variables.

I tend to use them in switch statements to provide a different scope for each case and in this way allowing me to define local variable with the same name at closest possible location of their use and to also denote that they are only valid at the case level.

It is not so much a feature of C# than it is a logical side-effect of many C syntax languages that use braces to define scope.

In your example the braces have no effect at all, but in the following code they define the scope, and therefore the visibility, of a variable:

This is allowed as i falls out of scope in the first block and is defined again in the next:

{
{
int i = 0;
}


{
int i = 0;
}
}

This is not allowed as i has fallen out of scope and is no longer visible in the outer scope:

{
{
int i = 0;
}


i = 1;
}

And so on and so on.

I consider {} as a statement that can contain several statements.

Consider an if statement that exists out of a boolean expression followed by one statement. This would work:

if (true) Console.Write("FooBar");

This would work as well:

if (true)
{
Console.Write("Foo");
Console.Write("Bar");
}

If I'm not mistaken this is called a block statement.

Since {} can contain other statements it can also contain other {}. The scope of a variable is defined by it's parent {} (block statement).

The point that I'm trying to make is that {} is just a statement, so it doesn't require an if or whatever...

Because C++ (and java) allowed code blocks without a preceding statement.

C++ allowed them because C did.

You could say it all comes down to the fact that USA programme language (C based) design won rather than European programme language (Modula-2 based) design.

(Control statements act on a single statement, statements can be groups to create new statements)

The general rule in C-syntax languages is "anything between { } should be treated as a single statement, and it can go wherever a single statement could":

  • After an if.
  • After a for, while or do.
  • Anywhere in code.

For all intents and purposes, it's as the language grammar included this:

     <statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>

That is, "a statement can be composed of (various things) or of an opening brace, followed by a statement list (which may include one or more statements), followed by a closed brace". I.E. "a { } block can replace any statement, anywhere". Including in the middle of code.

Not allowing a { } block anywhere a single statement can go would actually have made the language definition more complex.

// if (a == b)
// if (a != b)
{
// do something
}

1Because...Its Maintain the Scope Area of the statement.. or Function, This is really useful for mane the large code..

{
{
// Here this 'i' is we can use for this scope only and out side of this scope we can't get this 'i' variable.


int i = 0;
}


{
int i = 0;
}
}

enter image description here

You asked "why" C# allows code blocks without preceeding statements. The question "why" could also be interpreted as "what would be possible benefits of this construct?"

Personally, I use statement-less code blocks in C# where readability is greatly improved for other developers, while keeping in mind that the code block limits the scope of local variables. For example, consider the following code snippet, which is a lot easier to read thanks to the additional code blocks:

OrgUnit world = new OrgUnit() { Name = "World" };
{
OrgUnit europe = new OrgUnit() { Name = "Europe" };
world.SubUnits.Add(europe);
{
OrgUnit germany = new OrgUnit() { Name = "Germany" };
europe.SubUnits.Add(germany);


//...etc.
}
}
//...commit structure to DB here

I'm aware that this could be solved more elegantly by using methods for each structure level. But then again, keep in mind that things like sample data seeders usually need to be quick.

So even though the code above is executed linearly, the code structure represents the "real-world" structure of the objects, thus making it easier for other developers to understand, maintain and extend.