[ Team LiB ] |
2.9 StatementsExecution in a C# program is specified by a series of statements that execute sequentially in the textual order in which they appear. All statements in a procedural-based language such as C# are executed for their effect. For instance, a statement may assign an expression to a variable, repeatedly execute a list of statements, or jump to another statement. So that multiple statements can be grouped together, zero or more statements may be enclosed in braces to form a statement block. 2.9.1 Expression Statements[variable =]? expr; An expression statement evaluates an expression, either assigning its result to a variable or generating side effects (i.e., invocation, new, ++, --). An expression statement ends in a semicolon. For example: x = 5 + 6; // assign result x++; // side effect y = Math.Min(x, 20); // side effect and assign result Math.Min(x, y); // discards result, but ok, there is a side effect x = = y; // error, has no side effect, and does not assign result 2.9.2 Declaration StatementsThe variable declaration syntax is: type [variable [ = expr ]?]+ ; The constant declaration syntax is: const type [variable = constant-expr]+; A declaration statement declares a new variable, optionally assigning the result of an expression to that variable. A declaration statement ends in a semicolon. The scope of a local or constant variable extends to the end of the current block. You cannot declare another local variable with the same name in the current block or in any nested blocks. For example: bool a = true; while(a) { int x = 5; if (x= =5) { int y = 7; int x = 2; // error, x already defined } Console.WriteLine(y); // error, y is out of scope } A constant declaration is like a variable declaration, except that the variable cannot be changed after it has been declared: const double speedOfLight = 2.99792458E08; speedOfLight+=10; // error 2.9.3 Selection StatementsC# has many ways to conditionally control the flow of program execution. This section covers the simplest two constructs: the if-else statement and the switch statement. In addition, C# also provides the conditional operator and loop statements that conditionally execute based on a boolean expression. Finally, C# provides object-oriented ways of conditionally controlling the flow of execution, namely virtual method invocations and delegate invocations. 2.9.3.1 The if-else statementif (Boolean-expr) [statement | statement-block] [ else [statement | statement-block] ]? An if-else statement executes code depending on whether a boolean expression is true. Unlike in C, only a boolean expression is permitted. In this example, the Compare method will return 1 if a is greater than b, -1 if a is less than b, and 0 if a is equal to b. int Compare(int a, int b) { if (a>b) return 1; else if (a<b) return -1; return 0; } It is very common to use the && and || and ! operators to test for AND, OR, and NOT conditions. In this example, our GetUmbrellaNeeded method returns an umbrella if it's rainy or sunny (to protect us from the rain or the sun), as long as it's not also windy (since umbrellas are useless in the wind): Umbrella GetUmbrella (bool rainy, bool sunny, bool windy) { if ((rainy || sunny) && ! windy) return umbrella; return null; } 2.9.3.2 The switch statementswitch (expr) { [ case constant-expr : statement* ]* [ default : statement* ]? } switch statements let you branch program execution based on a selection of possible values a variable may have. switch statements may result in cleaner code than multiple if statements, since switch statements require an expression to be evaluated only once. For instance: void Award(int x) { switch(x) { case 1: Console.WriteLine("Winner!"); break; case 2: Console.WriteLine("Runner-up"); break; case 3: case 4: Console.WriteLine("Highly commended"); break; default: Console.WriteLine("Don't quit your day job!"); break; } } The switch statement can only evaluate a predefined type (including the string type) or enum, though user-defined types may provide an implicit conversion to these types. The end of each case statement must be unreachable. This typically means each case statement ends with a jump statement. The options are:
Unlike in Java and C++, the end of a case statement must explicitly state where to go to next. There is no error-prone "default fall through" behavior; not specifying a break results in the next case statement being executed: void Greet(string title) { switch (title) { case null: Console.WriteLine("And you are?"); goto default; case "King": Console.WriteLine("Greetings your highness"); // error, should specify break, otherwise... default : Console.WriteLine("How's it hanging?"); break; } } 2.9.4 Loop StatementsC# enables a sequence of statements to execute repeatedly with the while, do while, for, and foreach statements. 2.9.4.1 while loopswhile (Boolean-expr) [statement | statement-block] while loops repeatedly execute a statement block when a boolean expression is true. The expression is tested before the statement block is executed. For example: int i = 0; while (i<5) { Console.WriteLine (i); i++; } output: 0 1 2 3 4 2.9.4.2 do-while loopsdo [statement |statement-block] while (Boolean-expr); do-while loops differ only in functionality from while loops in that they allow the expression to be tested after the statement block has executed. In this example, a do-while loop prints 8, while a while loop would have not printed anything. For example: int i = 8; do { Console.WriteLine (i); i++; } while (i<5); output: 8 2.9.4.3 for loopsfor (statement?; Boolean-expr?; statement?) [statement | statement-block] for loops can be more convenient than while loops when you need to maintain an iterator value. As in Java and C, for loops contain three parts. The first part is a statement executed before the loop begins, and by convention is used to initialize an iterator variable; the second part is a boolean expression that, while true, will execute the statement block, and the third part is a statement executed after each iteration of the statement block, which convention is used to iterate the iterator variable. For example: for (int i=0; i<10; i++) Console.WriteLine(i); Any of the three parts of the for statement may be omitted. One can implement an infinite loop such as the following (though while (true) may be used instead): for (;;) Console.WriteLine("Hell ain't so bad"); 2.9.4.4 foreach loopsforeach ( type-value in IEnumerable ) [statement | statement-block ] It is very common for for loops to iterate over a collection, so C#, like Visual Basic, has a foreach statement. For instance, instead of doing the following: for (int i=0; i<dynamite.Length; i++) Console.WriteLine(dynamite [i]); You can perform this action: foreach (Stick stick in dynamite) Console.WriteLine(stick); The foreach statement works on any collection (including arrays). Although not strictly necessary, all collections leverage this functionality by supporting IEnumerable and IEnumerator, which are explained in Chapter 7. Here is an equivalent way to iterate over our collection: IEnumerator ie = dynamite.GetEnumerator( ); while (ie.MoveNext( )) { Stick stick = (Stick)ie.Current; Console.WriteLine(stick); } Under the hood, the foreach statement also acts as a using statement (covered later in this chapter) on the enumerator object (ie in the example above). In Visual C# 2003, Dispose( ) will be called on the enumerator, even if the enumerator does not implement IEnumerable. 2.9.5 Jump StatementsThe C# jump statements are break, continue, goto, return, and throw. All jump statements obey sensible restrictions imposed by try statements (see Section 4.6 in Chapter 4). First, a jump out of a try block always executes the try's finally block before reaching the target of the jump. Second, a jump cannot be made from the inside to the outside of a finally block. 2.9.5.1 The break statementbreak; The break statement transfers execution from the enclosing while loop, for loop, or switch statement block to the next statement block. int x = 0; while (true) { x++; if (x>5) break; // break from the loop } 2.9.5.2 The continue statementcontinue; The continue statement forgoes the remaining statements in the loop and makes an early start on the next iteration. int x = 0; int y = 0; while (y<100) { x++; if ((x%7)= =0) continue; // continue with next iteration y++; } 2.9.5.3 The goto statementgoto statement-label; goto case-constant; The goto statement transfers execution to another label within the statement block. A label statement is just a placeholder in a method: int x = 4; start: x++; if (x= =5) goto start; The goto case statement transfers execution to another case label in a switch block (as explained earlier in the "Switch" section). 2.9.5.4 The return statementreturn expr?; The return statement exits the method, and must return an expression of the method's return type if the method is nonvoid. int CalcX(int a) { int x = a * 100; return x; // return to the calling method with value } 2.9.5.5 The throw statementthrow exception-expr?; The throw statement throws an exception to indicate an abnormal condition has occurred (see Section 4.6 in Chapter 4). if (w= =null) throw new ArgumentException("w can't be null"); 2.9.5.6 The lock statementlock (expr) [statement | statement-block] The lock statement is actually a syntactic shortcut for calling the Enter and Exit methods of the Monitor class (see Chapter 16). 2.9.5.7 The using statementusing (declaration-expr) [statement | statement-block] Many classes encapsulate nonmemory resources, such as file handles, graphics handles, or database connections. These classes implement System.IDisposable, which defines a single parameterless method named Dispose called to clean up these resources. The using statement provides an elegant syntax for declaring and then calling the Dispose method of variables that implement IDisposable. For example: using (FileStream fs = new FileStream (fileName, FileMode.Open)) { ... } This is precisely equivalent to: FileStream fs = new FileStream (fileName, FileMode.Open); try { ... } finally { if (fs != null) ((IDispoable)fs).Dispose( ); } For more on IDisposable, see Chapter 15. |
[ Team LiB ] |