Program Flow Control: Control Structures


An 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 Path

Building 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 Statements

Conditional 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 Structure

The 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 Combination

The 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 Evaluation

Many 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.

Table 3.2. Truth Table for Short Circuit Evaluations

Value

Operator

Value

Result

True

AND

True

True

True

AND

False

False

True

OR

True

True

True

OR

False

True


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 Work
    using System;    namespace ShortCircuitEvaluation    {        /// <summary>        /// Summary description for Class1.        /// </summary>        class Class1     {            static bool ReturnsTrue( ) {                Console.WriteLine( "*********[ EXECUTING ReturnsTrue ]***********" );                return true;            }            static bool ReturnsFalse( ) {                Console.WriteLine( "*********[ EXECUTING ReturnsFalse ]***********" );                return false;            }            /// <summary>            /// C# short Circuit evaluation example            /// </summary>            [STAThread]            static void Main(string[] args)    {                Console.WriteLine( "true AND ReturnsTrue( )" );                if( true && ReturnsTrue( ) ) {                    Console.WriteLine( "Evaluated trueExpression " +                       "and executed ReturnsTrue( )" );                }                Console.WriteLine( System.Environment.NewLine );                Console.WriteLine( "true AND ReturnsFalse( )" );                if( true && ReturnsFalse( ) ) {                    Console.WriteLine( "This won't execute" );                } else {                    Console.WriteLine( "Evaluated trueExpression " +                       "and executed ReturnsFalse( )" );                }                Console.WriteLine( System.Environment.NewLine );                Console.WriteLine( "true OR True evaluation" );                if( true || ReturnsTrue( ) ) {                    Console.WriteLine( "Evaluated only trueExpression " +                       "then short circuit. ReturnsTrue( ) was not executed" );                }                Console.WriteLine( System.Environment.NewLine );                Console.WriteLine( "true OR ReturnsFalse( )" );                if( true || ReturnsFalse( ) ) {                    Console.WriteLine( "Evaluated only trueExpression "+                       "then short circuit. ReturnsFalse( ) was not executed" );                }                Console.WriteLine( System.Environment.NewLine );                Console.WriteLine( "false AND ReturnsTrue( )" );                if( false && ReturnsTrue( ) ) {                    Console.WriteLine( "This won't execute" );                } else {                    Console.WriteLine( "Evaluated only falseExpression. "+                       "ReturnsTrue( ) was not executed" );                }                Console.WriteLine( System.Environment.NewLine );                Console.WriteLine( "false OR ReturnsTrue( )" );                if( false || ReturnsTrue( ) ) {                    Console.WriteLine( "Evaluated both false and ReturnsTrue()" );                }            }        }    } 

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 and begin stepping through the code. Remember, to set a breakpoint, place the cursor on the source line and press F9 or left-click in the channel for the line. To single step the execution, press F11, which allows for stepping into method calls.

Using the Ternary Operator

The 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:

[View full width]

double discount = preferredCustomer ? orderTotal > 1000 ? .10 : .05 : orderTotal > 2000 "+" ? .1 : .025;

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 Statement

The 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:

  • Each case statement that contains statements must have a break statement. This includes the default case.

  • Cases can fall through only if the case is empty, meaning that it does not have statements within its body.

  • To jump from one case statement to another, the dreaded goto statement is used.

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 Statement

[View full width]

 using 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,  bird)" );             string animal = Console.ReadLine( );             if( animal.ToLower( ).Equals( "dog" ) ) {                 Console.WriteLine( "Bark Bark" );             } else if( animal.ToLower( ).Equals( "cat" ) ) {                 Console.WriteLine( "Meow" );             } else if( animal.ToLower( ).Equals( "fish" ) ) {                 Console.WriteLine( "swim" );             } else if( animal.ToLower( ).Equals( "bird" ) ) {                 Console.WriteLine( "Poly want a cracker" );             } else {                     Console.WriteLine( "Nice pet" );                 }         }     } } 

Listing 3.5. Using the switch Statement to Improve Readability

[View full width]

 using 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,  bird)" );             string animal = Console.ReadLine( );             switch( animal.ToLower( ) ) {                 case "dog":                     Console.WriteLine( "Bark Bark" );                     break;                 case "cat":                     Console.WriteLine( "Meow" );                     break;                 case "fish":                     Console.WriteLine( "swim" );                     break;                 case "bird":                     Console.WriteLine( "Poly want a cracker" );                     break;                 default:                     Console.WriteLine( "Nice pet" );                     break;              }          }      }  } 

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."



    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net