Programming Concepts

I l @ ve RuBoard

For those of you moving from either C++ or Java, you will have a very small learning curve for C#. The syntax and productions found in the language are very similar to those found in C++ or Java. The truth of the matter is that C# was designed to be simple to learn and powerful enough to be extremely expressive.

At the time I'm writing this, Microsoft has made available the C# language reference that includes the EBNF grammar for the language. Although I happen to enjoy reading language grammars, most of my peers think that's a little excessive. So, rather than put you to sleep with such mundane details, we will look at the language from a slightly higher level.

Namespaces

In recent years , the prevalence of namespaces has come to play a major role in software engineering and component development. Namespaces provide for isolation and packaging of related classes, interfaces, and struct s into a logical unit.

The .NET framework makes use of nested namespaces stemming from the System namespace. Microsoft has also provided classes and interfaces located under the Microsoft namespace for Windows-specific functionality. When developing components for the .NET platform, you should use your company name as the outer namespace in which to contain all of your classes, interfaces, and component code.

A namespace declaration should precede any code you develop, although it is not required. The syntax for declaring a namespace is as follows :

 namespace some-namespace-name {         //classes, interfaces, structs, and so on } 

Making use of entities within a namespace can be accomplished two different ways. The easiest way to access entities within a namespace is to use the using directive. Consider the System namespace, which has been used in every example presented so far. The first line of code in the previous examples is the line

 using System; 

This directive instructs the compiler to use the System namespace to locate the names of classes used in the code body.

The second option is to make use of the fully qualified name of a particular entity. For example, the Console class exists within the System namespace. Rather than making use of the using directive, it is possible to use the fully qualified name instead, as shown in the following:

 System.Console.WriteLine("Fully Qualified Name Access"); 

Let's see namespaces in action. The sample code in Listing 2.1.4 implements two namespaces. Each namespace contains a Money class. It is important to understand that the two Money classes are not the same as far as C# is concerned . Even though the Money class is identical in declaration and implementation, C# sees two distinct classes distinguished by namespace.

Listing 2.1.4 Namespaces
 1: //File       :part02_04.cs  2: //Date       :12.28.2000  3: //Author     :Richard L. Weeks  4: //Purpose    :Demonstrate Namespaces  5:  6:  7: using System;  8:  9: 10: 11: namespace Foo { 12: 13:     public class Money { 14: 15:         private double m_Amount; 16: 17:         public Money( ) { 18:             Init( 0.0 ); 19:         } 20: 21:         public Money( double Amount ) { 22:             Init( Amount ); 23:         } 24: 25: 26:         public void Print( ) { 27:             Console.WriteLine("Foo.Money.Print  {0} ", m_Amount ); 28:         } 29: 30: 31:         private void Init( double Amount ) { 32:             m_Amount = Amount; 33:         } 34:     } 35: } 36: 37: namespace Bar { 38: 39:     public class Money { 40: 41:         private double m_Amount; 42: 43:         public Money( ) { 44:             Init( 0.0 ); 45:         } 46: 47:         public Money( double Amount ) { 48:             Init( Amount ); 49:         } 50: 51: 52:         public void Print( ) { 53:             Console.WriteLine("Bar.Money.Print  {0} ", m_Amount ); 54:         } 55: 56: 57:         private void Init( double Amount ) { 58:             m_Amount = Amount; 59:         } 60:     } 61: } 62: 63: 64: public class NamespaceTest { 65: 66:     public static void Main( ) { 67: 68:         Foo.Money fm = new Foo.Money(5.00); 69:         Bar.Money bm = new Bar.Money(5.00); 70: 71: 72:         fm.Print( ); 73:         bm.Print( ); 74: 75: 76:     } 77: } 

The code in Listing 2.1.4 declares two namespaces ” Foo and Bar . A Money class exists within each namespace. To make use of each Money class, the Main method creates an instance of each Money class by using the fully qualified name. One caveat to note is the using statement, there does not exist a keyword to un-use a namespace. Therefore, if you have two objects with the same name residing in different namespace, be sure to use qualified names rather than the using directive.

Statements

To control the execution flow of a given section of program code, there needs to exist some notion of one or more flow control statements. That is the meat of this particular section.

if

One of the most basic control statements is the if statement. Simply stated, the if statement evaluates a Boolean expression. The result of the Boolean expression determines whether or not a given line of code or a code segment will be executed. When the result of the Boolean expression is true , any code within the control body of the if statement is executed. When the condition expression is false , the code contained within the control body of the if statement is not executed.

The syntax for t he if statement is as follows:

 if( conditional-expression )     Single statement     or if( conditional-expression ) {     one or more statements } 

The conditional-expression can be a simple expression or a compound expression. It is important to note that the conditional-expression must evaluate to a Boolean result. In C and C++, any expression with a non-zero value is considered true and a zero value is considered false . C# employs stricter type checking and requires the conditional-expression to evaluate to either true or false (see Listing 2.1.5).

Listing 2.1.5 The if Statement
 1: //File      :part02_05.cs  2: //Date      :12.29.2000  3: //Author    :Richard L. Weeks  4: //Purpose   :C# if statement usage  5:  6:  7: using System;  8:  9: 10: 11: public class Statements { 12: 13: 14:     public static void Main( ) { 15: 16:         bool bSimple_1 = true; 17:         bool bSimple_2 = false; 18: 19: 20:         if( bSimple_1 ) 21:             Console.WriteLine("You should see this"); 22: 23:         if( bSimple_2 ) 24:             Console.WriteLine("You should not see this"); 25: 26:         //Complex 27:         if( bSimple_1 && !bSimple_2 ) 28:             Console.WriteLine("Will you see this?"); 29: 30: 31:         //Multiple Statements 32:         if( bSimple_1 ) { 33:             Console.WriteLine("Statement 1"); 34:             Console.WriteLine("Statement 2"); 35:         } 36:     } 37: } 

The example in Listing 2.1.5 demonstrates the basic semantics of the if statement. Expression evaluation also employs short-circuit evaluation. This means that when the expression is being evaluated from left to right, as soon as the expression evaluates to false , the entire expression is said to be false . Short-circuit evaluation is employed by languages such as C and C++, but Visual Basic does not make use of short-circuit evaluation for basic Boolean logic such as And and Or In VB.NET, two operators, AndAlso and OrElse , have been added that do make use of short-circuit evaluation.

if...else

The if...else construct is merely an extension of the standard if statement. Because the if statement only executes the code within its body when the conditional-expression is true , the else clause allows for the execution of code when the conditional-expression is false . Listing 2.1.6 makes use of the if-else construct to determine if an integer entered by the user is odd or even.

Listing 2.1.6 if...else Statement Usage
 1: //File      :part02_06.cs  2: //Author    :Richard L. Weeks  3: //Purpose   :C# if-else statement  4:  5: using System;  6:  7: public class StatementTest {  8:  9:     public static void Main( ) { 10:         Console.Write("Enter an number between 1 and 10: "); 11:         int i = Int32.Parse( Console.ReadLine( ) ); 12: 13:         //is the number in the proper range 14:         if( (i >= 1) && (i <= 10) ) { 15: 16:             //is the number even or odd? 17:             if( (i % 2) == 0 ) 18:                 Console.WriteLine("The number {0}  is even", i ); 19:             else 20:                 Console.WriteLine("The number {0}  is odd", i ); 21: 22:         }  else 23:            Console.WriteLine("You must enter a number between 1 and 10"); 24: 25:     } 26: } 

Let's take a minute and step through the code in Listing 2.1.6. On line 10, the program prompts the user to enter a number between 1 and 10. The next line makes use of the ReadLine method of the Console object to read the input from the user. Because the ReadLine method returns a string, it is necessary to convert the string to an integral value. This is accomplished by using the static method Parse implemented by the Int32 value-type.

The next step is to test the value entered and determine whether the value is within the required range. If the conditional-expression evaluates to true , the next step is to determine if the number is odd or even. To test for odd or even, the program makes use of the modulus operator. The modulus operator divides the right-side value by the left-side value and returns the remainder. Because the divisor is 2, all even numbers will have a remainder of zero and all odd numbers will not.

As previously stated, C# enforces strict type checking, and the expression on line 17 must evaluate to a Boolean result. In C and C++, the line of code could have been written as

 if( i % 2 ) 

However, the expression i % 2 produces in an integer result and not a Boolean result. For this reason, C# will reject the statement and issue an error.

Conditional Operator ?:

The conditional operator can be viewed as a compact if...else statement. Its best use is for assigning values to variables based on some conditional-expression. Both C, C++, and Visual Basic implement the conditional operator; Visual Basic uses the IIf(...) expression for this purpose. Unlike VB, C# employs short-circuit evaluation. Short-circuit evaluation means that only the necessary result is evaluated. In VB, both the true and false conditions are evaluated. This is inefficient and can even introduce subtle bugs .

The conditional operator has the following syntax.

 result = conditional-expression ? true expression : false expression 

Remember that C# requires all conditional expressions to evaluate to a Boolean expression. This is enforced due to C#'s strong type checking. Listing 2.1.7 is a revision of Listing 2.1.6 and makes use of the conditional operator for determining if the number entered is odd or even.

Listing 2.1.7 The Conditional Operator
 1: //File      :part02_07.cs  2: //Author    :Richard L. Weeks  3: //Purpose   :conditional-operator  4:  5:  6:  7: using System;  8:  9: 10: public class StatementTest { 11: 12: 13:     public static void Main( ) { 14: 15:         Console.Write("Enter an number between 1 and 10: "); 16:         int i = Int32.Parse( Console.ReadLine( ) ); 17: 18: 19:         //is the number in the proper range 20:         if( (i >= 1) && (i <= 10) ) { 21: 22:             //is the number even or odd? 23:             string odd_even = (i % 2) == 0 ? "even" : "odd"; 24: 25:             Console.WriteLine( "The number {0}  is {1} ", i, odd_even ); 26: 27:         }  else 28:            Console.WriteLine("You must enter a number between 1 and 10"); 29: 30:     } 31: } 

Line 23 in Listing 2.1.9 shows the use of the conditional operator. Here, a string variable odd_even is assigned a value based on the condition that (i % 2) == 0 . When the condition is true , the variable odd_even is assigned the constant string literal "even" . When the expression is false , the variable odd_even is then assigned the constant string literal "odd" .

In Listing 2.1.7, the conditional operator is used to replace four lines of code found in Listing 2.1.6, lines 17 to 20 specifically .

goto

Yes, the goto statement still survives. I can hear the software engineering purists screaming. Why does a modern language include the goto statement? The goto statement is used to immediately transfer program execution to a specified label. When the switch statement is covered, a concrete use of the goto statement will be unveiled.

There are times when the judicious use of the goto statement allows for tight and efficient code. On the other hand, using the goto statement as the primary means of logic control flow tends to produce spaghetti code.

There are a few constraints regarding the use of the goto statement. A goto statement cannot be used to jump into another method or out of the current method. The goto statement can only transfer control to a label that exists within the current scope.

The syntax for the goto statement should be familiar to those of you coming from C, C++, or VB. A destination label can be any combination of alphanumeric constants, given that the first position is a character element. The label name is then terminated with a colon ( : ) to denote that it is, in fact, a label and not some statement, expression, or variable.

The goto syntax is as follows:

 goto label-name; 

Listing 2.1.8 illustrates the basic use of the goto statement.

Listing 2.1.8 The goto Statement
 1: //File    :part02_08.cs  2: //Author  :Richard L. Weeks  3: //Purpose :Demonstrate the use of the goto statement  4:  5:  6: using System;  7:  8:  9: public class GotoTest { 10: 11:     public static void Main( ) { 12: 13: 14:          Console.WriteLine("about to goto label1"); 15:          goto label1; 16: 17:          Console.WriteLine("This will not print"); 18: 19:     label1: 20:          Console.WriteLine("label1 goto effective"); 21:     } 22: } 23: 

The example in Listing 2.1.8 demonstrates the basic use of the goto statement. On line 19, a label named label1 has been defined. The goto statement on line 15 directs the program flow to immediately jump to the specified label. This, in effect, causes all code between lines 15 and 19 to be jumped over. Notice that the WriteLine statement on line 17 states that This will not print .

When compiling the example, the C# compiler will issue a warning stating that there exists "Unreachable Code detected ." The unreachable code is found on line 17. Because the control execution jumps this segment of code, there is no reason for it to exist. Always be sure to heed compiler warnings and treat them as if they were compiler errors.

switch

There are many times when it is necessary to evaluate some condition and select among several possible choices or cases. This is the role of the switch statement. Given some expression to evaluate, the switch statement can be used to select a constant case to execute. Think of the switch statement as a multiple-choice implementation. Instead of using multiple nested if statements, the switch statement can be used.

The switch statement consists of an expression to evaluate and one or more constant values that represent the possible outcome cases.

 switch( expression ) {     case constant-expression:         statement(s)         jump-statement        [default: statement(s); jump-statement] } 

The controlling expression for the switch statement can be an integral or string type expression. Each constant case expression must be of the same type as the controlling expression, and no two cases can have the same constant expression.

Unlike C and C++, C# does not allow for one case to fall through into another case. To accomplish fall-through style execution, the goto keyword can be used to transfer control to another case. Each case must make use of a jump statement including the last case or the default case. Listing 2.1.9 shows the basic use of the switch statement.

Listing 2.1.9 The switch Statement
 1: //File     :part02_09.cs  2: //Author   :Richard L. Weeks  3: //Purpose  :The switch statement  using System;  4:  public class SwitchTest {  5:      public static void Main( ) {  6:          Console.WriteLine("Please make your selection");  7:             Console.WriteLine("1 Hamburger");  8:             Console.WriteLine("2 Cheese Burger");  9:             Console.WriteLine("3 Fish"); 10:          int Selection = int.Parse( Console.ReadLine( ) ); 11:          switch( Selection ) {              case 1: 12:                    Console.WriteLine("Hamburger"); 13:                 break; 14:              case 2: 15:                     Console.WriteLine("Cheese Burger"); 16:                 break; 17:              case 3: 18:                     Console.WriteLine("Fish"); 19:                 break; 20:              default: 21:                     Console.WriteLine("Unknown choice"); 22:                 break; 23:          } 24:     } 25: } 

Listing 2.1.9 presents an example of the switch statement in action. Each case expression is represented by some constant integral value. Notice that the break jump statement separates each case.

Because C# does not allow for case fall through (that is, execution cannot continue from one case to another), the goto statement can be used to transfer control to another case or the default case. Listing 2.1.10 uses the goto statement to transfer control from one case statement to another.

Listing 2.1.10 Using the goto Inside a Case Statement
 1: //File     :part02_10.cs  2: //Author   :Richard L. Weeks  3: //Purpose  :The switch statement and the use of goto  4:  5: using System;  6:  7: public class SwitchTest {  8:     public static void Main( ) {  9:         Console.WriteLine("Please make your selection"); 10:     Console.WriteLine("1 Hamburger"); 11:     Console.WriteLine("2 Cheese Burger"); 12:     Console.WriteLine("3 Fish"); int Selection = int.Parse( Console.ReadLine( ) ); 13:     switch( Selection ) {          case 1: 14:                Console.WriteLine("Hamburger"); 15:             goto case 4; 16:            case 2: 17:                 Console.WriteLine("Cheese Burger"); 18:             goto case 4; 19:           case 3: 20:                Console.WriteLine("Fish"); 21:             break; 22:           case 4: 23:                Console.WriteLine("Transferred to case 4"); 24:                Console.WriteLine("Transferring to default case"); 25:                goto default; 26:           default: 27:                 Console.WriteLine("Unknown choice"); 28:             break; 29:     } 30:   } 31: } 

Listing 2.1.10 is a modification of the code found in Listing 2.1.9. Cases 1, 2, and 4 make use of the goto statement to transfer control from the current case to another case. Again, the goto statement can be used to transfer control to another case label or to the default case label.

for

The for statement is one of the most basic iteration statements. Whenever there is a fixed number of iterations, the for statement fits the bill. Like C and C++, the for statement consists of an initialization, conditional expression, and an iteration statement. The syntax is as follows:

 for(  initialization(s);   conditional-expression;   iteration(s)  )     statement; 

The initialization can be a comma-separated list of variable declarations and assignments. The conditional expression must evaluate to a Boolean expression and is used to determine when the for loop terminates. The iteration section is used to increment or decrement the controlling variables used by the for statement (see Listing 2.1.11).

Listing 2.1.11 The for Statement
 1: using System; 2: 3: public class ForStatement { 4: 5:     public static void Main( ) { 6: 7:         for( int i = 0; i < 10; i++ ) 8:             Console.WriteLine( "i = {0} ", i ); 9:     } 

Listing 2.1.11 shows the for statement in action. The integer variable i is used to control the number of iterations to be performed by the for statement. The output produced by Listing 2.1.11 is as follows:

 i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 

Notice that the value of i ranges from 0 to 9, and not 0 to 10. This is due to the conditional expression i < 10; . Notice that the expression that equates to i is less than 10. When the value of i is equal to 10, the for statement will terminate and program execution will continue with the statement following the for statement construct.

The for statement controls only the next statement or statement block. To execute multiple statements, the statements must be contained within a statement block. A statement block is a section of statements within the opening and closing {} brackets. Listing 2.1.12 shows a for statement controlling a statement block.

Listing 2.1.12 Statement Block
 1: using System;  2:  3: public class ForTest {  4:  5:     public static void Main( ) {  6:  7:         for( int i = 0; i < 10; i++ ) {  8:             Console.WriteLine("value of i to follow");  9:             Console.WriteLine("i = {0} ", i); 10:         } 11:     } 12: } 

With the addition of a statement block, the for statement now controls the execution of statements within the block. The output from Listing 2.1.12 should look like the following:

 1: value of i to follow  2: i = 0  3: value of i to follow  4: i = 1  5: value of i to follow  6: i = 2  7: value of i to follow  8: i = 3  9: value of i to follow 10: i = 4 11: value of i to follow 12: i = 5 13: value of i to follow 14: i = 6 15: value of i to follow 16: i = 7 17: value of i to follow 18: i = 8 19: value of i to follow 20: i = 9 

A small note about variable scooping. In each of the examples detailing the use of the for statement, the control variable was declared and initialized within the for statement itself. As such, the variable i is only visible within the for statement, and any attempt to access the variable after the for statement will result is a compiler error.

while

The while statement allows for the execution of the statement body as long as the conditional expression evaluates to true .

 while( conditional-expression )     statement 

The while statement operates as follows:

  1. The conditional expression is tested .

  2. If the conditional expression is true , the statement body is executed.

  3. This continues until the condition being evaluated is false .

  4. When the condition is false , the statement exits and execution beings at the next line of code following the statement.

For this reason, the body of the while statement may not execute at all; if the condition is false , the body of the statement will not execute.

The while statement is useful when the number of iterations is unknown, unlike the for statement, which is generally deterministic and a known quantity of iterations is required.

Consider the implementation of Newton's method for determining square roots. The number of iterations is unknown because the method will need to run as long as the delta between the previous result and the current result is larger than some predefined epsilon value. Let's look at the pseudo code for Newton's method and then the C# implementation.

 Epsilon := 1.0e-9 BaseGuess := N       //Can be any value Value := M           //Some user defined value NewGuess := ((Value / BaseGuess) + BaseGuess) / 2; While abs_delta( NewGuess , BaseGuess ) > Epsilon Begin       BaseGuess := NewGuess;       NewGuess := ((Value / BaseGuess) + BaseGuess) / 2; End 

Notice that there is no way to determine the number of iterations the while statement will execute. The controlling expression is not based on a counter, but rather a Boolean evaluation that can be true at any time. This undetermined number of iterations is well suited to the while statement rather than the for statement, which should be used when the number of iterations is deterministic. The previous pseudo code for Newton's method can easily be expressed in C# with the code in Listing 2.1.3.

Listing 2.1.13 The while Statement
 1: //File    :part02_13.cs  2: //Author  :Richard L. Weeks  3: //Purpose :Make use of the while statement to  4: //        :implement Newton's method for finding  5: //        :the square root of a number.  6:  7: using System;  8:  9: 10: 11: public class Newton { 12: 13:    public static void Main( ) { 14: 15: 16:     const double epsilon   = 1.0e-9; 17:           double dGuess    = 11.0; 18: 19:     //Prompt the user for a positive number and obtain their input 20:     Console.Write("Enter a positive number: "); 21:     double dValue = double.Parse( Console.ReadLine( ) ); 22: 23:     //Calculate the Initial result value 24:         double dResult = ((dValue / dGuess) + dGuess) / 2; 25: 26:         Console.WriteLine( "Guess Value  = {0} ", dGuess  ); 27:         Console.WriteLine( "Result Value = {0} ", dResult ); 28: 29:     //Continue to approximate the sqr until the delta is less than epsilon 30:         while( Math.Abs(dResult - dGuess) > epsilon ) { 31: 32:             dGuess = dResult; 33:         dResult = ((dValue / dGuess) + dGuess) / 2; 34: 35:             Console.WriteLine( "Guess Value  = {0} ", dGuess  ); 36:             Console.WriteLine( "Result Value = {0} ", dResult ); 37:     } 38: 39:     Console.WriteLine( "\n****\nThe approx sqrt of {0}  is {1} \n****", dValue, graphics/ccc.gif dResult ); 40:     } 41: } 

The implementation of Newton's method is merely a straightforward conversion of the pseudo code listed previously. There are a few subtle items to point out. Line 21 shows an example of the primitive type double and the Parse method. Remember that C# implements primitive types as struct s and that a struct can also contain methods . This is the case with all primitive types in C#.

The next item of interest is the while statement and the controlling conditional expression on line 30. Notice the Abs method, which is a static method of the Math class. The Abs method returns the absolute value of the given integral expression.

do...while

A similar construct to the while statement is the do...while statement. Unlike the while statement, the body of the do...while statement will always execute at least one iteration. This is due to the fact that the conditional expression is tested at the end of each loop rather than at the beginning. Listing 2.1.14 is a modification of Listing 2.1.13 that replaces the use of the while statement with the do...while statement. The result produced by each listing is the same, only the semantics of what is happening has changed.

Listing 2.1.14 The do...while Statement
 1: //File    :part02_14.cs  2: //Author  :Richard L. Weeks  3: //Purpose :Make use of the do while statement to  4: //        :implement Newton's method for finding  5: //        :the square root of a number.  6:  7: using System;  8:  9: public class Newton { 10: 11:    public static void Main( ) { 12: 13: 14:     const double epsilon   = 1.0e-9; 15:           double dGuess    = 11.0; 16:           double dResult   = 0.0; 17: 18:     //Prompt the user for a positive number and obtain their input 19:     Console.Write("Enter a positive number: "); 20:     double dValue = double.Parse( Console.ReadLine( ) ); 21: 22:     //Calculate the initial result 23:     dResult = ((dValue / dGuess) + dGuess) / 2; 24: 25:     //Continue to approximate the sqr until the delta is less than epsilon 26:     do { 27:             Console.WriteLine( "Guess Value  = {0} ", dGuess  ); 28:             Console.WriteLine( "Result Value = {0} ", dResult ); 29: 30:             dGuess = dResult; 31:         dResult = ((dValue / dGuess) + dGuess) / 2; 32: 33:         }  while( Math.Abs(dResult - dGuess) > epsilon ); 34: 35: 36:     Console.WriteLine( "\n****\nThe approx sqrt of {0}  is {1} \n****", dValue, graphics/ccc.gif dResult ); 37:     } 38: } 
foreach

The foreach statement will be familiar to those of you who have done development with Visual Basic. Essentially, the foreach statement allows for iteration over the elements withi n an array or any collection that implements the IEnumerable interface. Interfaces will be covered in detail later in this section.

Every collection provides some method for iterating through the contents of the container. In the C++ STL world, there exists the concept of an iterator; this is orthogonal to the concept of an enumerator in the world of COM. Anyone who has had the pleasure of implementing the IEnumVARIANT interface will appreciate the ease of implementing the IEnumerable interface along with providing an IEnumerator interface available in the .NET framework.

 foreach(  element_type  variable in expression )     statement; 

Looking at the syntax of the foreach statement, the element_type is the data type to be used as the variable declaration. The expression can be an array or a collection class that contains elements of type element_type . Listing 2.1.15 uses the foreach statement to iterate over the contents of an integer array.

Listing 2.1.15 The foreach Statement
 1: //File   :part02_15.cs  2: //Author :Richard Weeks  3: //Purpose:Using the foreach statement  4:  5:  6: using System;  7: public class ArrayListing {  8:  9:     public static void Main( ) { 10: 11:        int[] whole_numbers = {1,2,3,4,5,6,7,8,9,10} ; 12: 13: 14:        //Display each element in the whole_numbers array 15:        foreach( int value in whole_numbers ) 16:           Console.WriteLine( "value = {0} ", value ); 17:     } 18: } 

There is not a lot of code in Listing 2.1.15 because the focus is on putting the foreach statement to work. When you look under the covers of the foreach statement, lines 15 and 16 of Listing 2.1.15 are equivalent to the following code segment in Listing 2.1.16.

Listing 2.1.16 Expanding the foreach Statement
 1: IEnumerator iterator = whole_numbers.GetEnumerator( ); 2: while( iterator.MoveNext( ) ) { 3:     int value = (int)iterator.Current; 4:     Console.WriteLine( "value = {0} ", value ); 5: } 

As you can see, the expanded code makes use of the IEnumerator interface and the GetEnumerator() method provided by the System.Array type. Next, a while statement is used to enumerate the elements of the array. The current element is accessed and cast to the proper type. When the type requested is a primitive type, this step requires unboxing the element from the object type and placing the value into the appropriate primitive type.

Operators

Operators are actions that can be applied to primitive types and object types that provide the operator implementation. Unary operators are operations that only act on a single entity. Binary operators require both a left and right side value on which to operate . The relational operators evaluate to Boolean expressions that can be used to form conditional expressions. Table 2.1.2 contains the available operators found in C#.

Table 2.1.2. C# Operators
Operator Category Operator
Arithmetic +, -, *, /, %,
Logical (Boolean and Bitwise) &, , ^, !, ~, &&, , true, false
Increment, Decrement ++, ”
Shift >>, <<
Relational ==, !=, <, >, <=, >=
Assignment =, +=, -=, *=, /=, %=, !=, ^=, <<=, >>=
Type Information is
Casting (Type)Variable, as

The C# reference contains a full listing of not only unary and binary operators, but also indexing, member access, indirect access, expanded type information, and casting. The operators in Table 2.1.2 will be familiar to programmers of most languages with the exception of is and as . These two operators need some further explanation; each operator accomplishes similar, but slightly different tasks .

The is operator

The is operator is used to test if an entity is of a certain type. C# supports a very robust runtime type information and the is operator uses this type information to determine if the given entity is of the requested type.

 expression is type 

The is operator evaluates to a Boolean result and can be used as a conditional expression. The is operator will return true if the following conditions are met:

  • The expression is not null.

  • The expression can be safely cast to the type. The cast assumes an explicit cast in the form of ( type )( expression ) .

If both of these conditions are satisfied, the is operator will return a Boolean true; otherwise , the is operator will return false . Listing 2.1.17 demonstrates the use of the is operator.

Listing 2.1.17 The is Operator
 1: //File        :part02_16.cs  2: //Author    :Richard L. Weeks  3: //Purpose    :Demonstrate the 'is' operator  4:  5:  6: using System;  7:  8: //Create two empty classes.  We only need their declaration for  9: //the purpose of demonstrating the is keyword 10: 11: class Dog { 12: } 13: 14: class Cat { 15: } 16: 17: 18: public class IsDemo { 19: 20:     public static void Main( ) { 21: 22:         Dog myDog = new Dog( ); 23:         Cat myCat = new Cat( ); 24:         int i = 10; 25: 26:         WhatIsIt(myDog); 27:         WhatIsIt(myCat); 28:         WhatIsIt(i); 29:     } 30: 31:     public static void WhatIsIt( object o ) { 32: 33:         if( o is Dog ) 34:             Console.WriteLine("It is a dog"); 35:         else if( o is Cat ) 36:             Console.WriteLine("It is a cat"); 37:         else 38:             Console.WriteLine("I don't know what it is"); 39:     } 40: } 

The is example in Listing 2.1.17 actually introduces two concepts not yet discussed. The first is the creation of a static method WhatIsIt in the IsDemo class. A static method can be used like a standalone function because no object instance is required. Static methods will be covered in detail when classes are covered later in this section.

The next item of interest is the parameter being passed to the static WhatIsIt method. Notice that the formal parameter is object . In C#, all classes implicitly inherit from the base class object and all value types can be boxed as object . Because this is the case, object can be used as a generic type that accepts anything.

The actual use of the is operator is fairly straightforward. Within each if statement, the is operator is used to determine the runtime type information of the object passed in. Depending on the results of the is expression, the appropriate response will be displayed to the console.

The following is the output of Listing 2.1.16.

 It is a dog It is a cat I don't know what it is 
The as Operator

Like the is operator, the as operator makes use of runtime type information in an attempt to cast a given expression to the requested type. The normal casting operator ” ( T ) e , where T is the type and e is the expression ”generates an InvalidCastException when there is no valid cast. The as operator does not throw an exception; instead, the result returned is null.

The as operator uses the same syntax as the is operator:

 expression as type 

The as syntax can be formally expanded into the following:

 expression is type ? (type)expression : (type)null 

The as operator is therefore merely shorthand notation for using both the is operator and the conditional operator. The benefit of the as operator is its ease of use and the fact that no exception is thrown in the event that a type safe cast does not exist.

I l @ ve RuBoard


C# and the .NET Framework. The C++ Perspective
C# and the .NET Framework
ISBN: 067232153X
EAN: 2147483647
Year: 2001
Pages: 204

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