Program Flow Control: Control StructuresAn application simply cannot function without control structures. The following sections will show you how programs written in C# execute code and in what order, as well as how you can change the way code executes with loops, conditionals, and more. The Program Execution PathBuilding an application requires the translation of business requirements into code. To implement business rules and application logic, it's necessary to have the ability to handle various conditions such as Hourly Wage > 50 and take the appropriate action. The next section is a guide through the control structures that C# offers to implement application logic, conditional processing, and looping. Most of what follows should be familiar to anyone with previous programming knowledge. However, there are some twists that you might not be aware of. Conditional StatementsConditional statements form the heart of decision-making logic. They allow for business logic such as "If customer order is greater than 100 dollars, offer 10% discount; else, offer 5% discount." C# offers several mechanisms to implement such logic. Something that needs to be pointed out before venturing too far is that C# requires conditional expressions to be boolean; that is, they evaluate to true or false. Languages such as C/C++ are not as strict and allow for expressions to merely evaluate to zero/nonzero in order to determine the process flow. This is not the case with C#. The C# compiler will quickly issue an error message if the expression does not evaluate to a type-safe boolean expression. The if Control StructureThe if conditional statement represents the most basic of program flow control structures. The if statement evaluates a boolean expression to determine whether to execute one or more statements. By default, the if statement controls the execution of the very next statement. However, the use of code blocks allows the if statement to control several statements. Code blocks are statements contained within the { and } characters. The following code snippets illustrate this concept. Controlling a single statement: if( boolean expression is true ) someStatement( ); //Controlled by the if statement thisStatementAlwaysExecutes( ); or if( boolean expression is true ) //controls the execution of code between { and } brackets { statement_1(); statement_2(); } The if/else Control Structure CombinationThe extension of the if statement is the if/else combination, which allows for the if statement to control two code blocks. When the condition being evaluated is true, the first control statement(s) is executed; otherwise, the else block is executed. This allows for the statement "If customer order is greater than 100 dollars, offer 10% discount; else, offer 5% discount" to be easily implemented as follows: if( customerOrderTotal > 100 ) discount = .10; //10% discount else discount = .05; //5% discount In addition, the if/else statement can make use of code blocks to control the execution of multiple statements: if( customerOrderTotal > 100 ) { Console.WriteLine( "Applying a 10% discount" ); discount = .10; //10% discount } else { Console.WriteLine( "Applying a 5% discount" ); discount = .05; //5% discount } Short Circuit EvaluationMany times the expression being evaluated is a compound expression. A compound expression is two or more conditions to be evaluated such as "Customer is a preferred customer and order amount > 1000, apply a 15% discount." In this case, two different conditions must evaluate to true for the specified action to occur. C# takes a shortcut approach to evaluate the need to perform a full evaluation of every expression. For instance, if there are two expressions to evaluate and both must be true for the full statement to be true, C# evaluates the first statement. If the first statement is false, there is no need to even evaluate the second statement because the entire expression will be false regardless. Table 3.2 provides a basic truth table that further illustrates this point.
Such short-circuit evaluations save processing cycles and improve code performance by eliminating unnecessary code execution. The code in Listing 3.3 shows various short circuit evaluations in action. Listing 3.3. Understanding How Short Circuit Evaluations Workusing System; namespace ShortCircuitEvaluation The code in Listing 3.3 exercises the short-circuit evaluation feature of C#. The best way to understand what is happening in the code is to set a breakpoint on line 27 Using the Ternary OperatorThe ternary operator is a very compact version of an if/else statement. Although a handy shortcut, overuse of the ternary operator can lead to very terse code and should be used only when really needed for very simple expressions. The syntax for the ternary operator is as follows: result = <expression> ? <statement 1> : <statement 2>; When the expression is true, statement 1 is executed; otherwise, statement 2 is executed. Notice that the ternary operator expects to return a result. So, for implementing "if order total > 1000, apply 10% discount; else 5% discount" would be implemented as follows: double discount = orderTotal > 1000 ? .10 : .5; I suggest that using the ternary operator should not create expressions any more complex than the previous example. After all, the statements being executed can in fact be as complex as another nested ternary operator. For instance, consider the following: double discount = preferredCustomer ? orderTotal > 1000 ? .10 : .05 : orderTotal > 2000 Any idea what that snippet of code does? Create a small project and type in the code to see what it does. Again, the key point is to develop readable code, not cryptic code. The switch StatementThe idea of the switch statement is to alleviate excessive if statements and to offer a clean approach to handling multiple conditions for a given expression. The switch statement can be thought of as a multiple-choice-style statement. The syntax for the switch statement is as follows: switch( expression ) { case const-expression-1: one or more statements; break; case const-expression-2: one or more statements; break; case const-expression-3: one or more statements; break; . . . default: one or more statements; break; } The expression to be evaluated can be an integer, character, string, or enum. Each case statement expression must be a const value, meaning that it is defined at compile time and not runtime. For instance, the case expression cannot be the result of a method call or a variable that can change its value. The switch statement evaluates each case statement until a match is found. If no match is found, the default case is used. The default case is not required, but allows for a catch-all case for evaluation. There are a few things about the switch statement to keep in mind:
NOTE The statements within each case block can be any valid C# statement, including method calls and return statements. However, it is best to keep the code within each case short and simple by keeping the number of statements to a minimum. Again, the main purpose of the switch statement is to provide a cleaner mechanism than using multiple if-else-if combinations. Consider the following two listings. Listing 3.4 uses multiple if-else-if statements for evaluation, whereas Listing 3.5 uses the switch statement to accomplish the same task. Listing 3.4. Unnecessary Clutter with if-else-if Statementusing System; namespace ifelseif { /// <summary> /// Cluttered ifelseif sample /// </summary> class Class1 { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { Console.Write( "Enter the type of pet " +" you own: (example dog, cat, fish, Listing 3.5. Using the switch Statement to Improve Readabilityusing System; namespace SwitchStatement { class Class1 { /// <summary> ///Demonstrates the usage of the switch statement /// </summary> [STAThread] static void Main(string[] args) { Console.Write( "Enter the type of pet" +" you own: (example dog, cat, fish, Although Listings 3.4 and 3.5 both implement the same overall functionality, the switch statement provides several advantages for this type of situation. First, the readability of the code is improved. Second, the animal.ToLower( ).Equals( ) method that was used in Listing 3.4 is reduced to a single use rather than five. This is a performance gain, as will be discussed in Chapter 4, "Strings and Regular Expressions." |