Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
197,1 KB
Nội dung
32 | Chapter 3: C# Language Fundamentals Strings It is nearly impossible to write a C# program without creating strings. A string object holds a series of characters. You declare a string variable using the string keyword much as you would create an instance of any object: string myString; You create a string literal by placing double quotes around a string of letters: "Hello World" It is common to initialize a string variable with a string literal: string myString = "Hello World"; We cover strings in much greater detail in Chapter 10. Identifiers An identifier is just the name the programmer chooses for the types, methods, vari- ables, constants, objects, and so on in the program. An identifier must begin with a letter or an underscore, and remember that identifiers are case-sensitive, so C# treats someName and SomeName as two different identifiers. It is normally not good programming practice to create two variables or classes with names that are differentiated only by capitalization. Although the compiler will not be confused, the programmer will be, and the cost of attempting to maintain such a program can be very high. The exception to this is the common practice of having a member vari- able (explained in Chapter 4) and a property with the same name, differentiated only by using camel notation for the former, and Pascal notation for the latter. The Microsoft naming conventions suggest using camel notation (initial lowercase, such as someVariable) for variable names, and Pascal notation (initial uppercase, such as SomeMethodOrProperty) for method names and most other identifiers. Microsoft recommends against Hungarian notation (e.g., iSomeInteger) and underscores (e.g., Some_Value). Microsoft’s Charles Simonyi (who was born September 10, 1948, in Budapest) invented Hungarian nota- tion, and it was very useful when languages were limited to a small number of types. Along with nearly 2 billion other interesting articles, Wikipedia (http:// en.wikipedia.org) provides extensive articles on Hungarian notation, on Charles Simonyi, and on Richard Dawkins, who holds the Charles Simonyi Chair for Public Understanding of Science at Oxford University. Statements | 33 Whitespace In the C# language, spaces, tabs, and newlines are considered to be “whitespace” (so named because you see only the white of the underlying “page”). Extra whitespace is generally ignored in C# statements. You can write: myVariable = 5; or: myVariable = 5; and the compiler will treat the two statements as identical. The key word in the preceding rule is “extra” whitespace. Some whitespace is not extra; it is required to allow the compiler to differentiate one word from another. Thus, if you were to enter: int myVariable = 5; // no problem or: int myVariable=5; // no problem both would compile, because the spaces between the identifier myVariable, the assignment operator ( =), and the literal value 5 are “extra.” If, however, you were to enter: intMyVariable=5; // error you would receive a compiler error, because the space between the keyword int and the identifier myVariable is not extra, it is required. Another exception to the “whitespace is ignored” rule is within strings. If you write: Console.WriteLine("Hello World"); each space between “Hello” and “World” is treated as another character in the string. Most of the time, the use of whitespace is intuitive. The key is to use whitespace to make the program more readable to the programmer; the compiler is typically indifferent. VB programmers take note: in C# the end-of-line has no special signifi- cance; you end statements with semicolons, not newline characters. There is no line-continuation character because none is needed. Statements In C#, a complete program instruction is called a statement. Programs consist of sequences of C# statements. Virtually every statement ends with a semicolon ( ;). For example: 34 | Chapter 3: C# Language Fundamentals int x; // a statement x = 23; // another statement int y = x; // yet another statement C# statements are evaluated in order. The compiler starts at the beginning of a state- ment list and makes its way to the end. This would be entirely straightforward, and terribly limiting, were it not for branching. There are two types of branches in a C# program: unconditional branches and conditional branches. Program flow is also affected by looping and iteration statements, which are signaled by the keywords for, while, do, in, and foreach. I discuss iteration later in this chap- ter. For now, let’s consider some of the more basic methods of conditional and unconditional branching. Unconditional Branching Statements You can create an unconditional branch in one of two ways. The first way is by invoking a method. When the compiler encounters the name of a method, it stops execution in the current method and branches to the newly “called” method. When that method returns a value, execution picks up in the original method on the line just below the method call. Example 3-6 illustrates. Program flow begins in Main( ) and proceeds until SomeMethod( ) is invoked (invok- ing a method is also referred to as “calling” the method). At that point, program flow Example 3-6. Calling a method using System; namespace CallingAMethod { class CallingAMethod { static void Main( ) { Console.WriteLine("In Main! Calling SomeMethod( ) "); SomeMethod( ); Console.WriteLine("Back in Main( )."); } static void SomeMethod( ) { Console.WriteLine("Greetings from SomeMethod!"); } } } Output: In Main! Calling SomeMethod( ) Greetings from SomeMethod! Back in Main( ). Statements | 35 branches to the method. When the method completes, program flow resumes at the next line after the call to that method. The second way to create an unconditional branch is with one of the unconditional branch keywords: goto, break, continue, return,orthrow. I provide additional information about the first three jump statements later in this chapter. The return statement returns control to the calling method. I discuss the final statement, throw, in Chapter 11. Conditional Branching Statements A conditional branch is created by a conditional statement, which is signaled by a keyword such as if, else,orswitch. A conditional branch occurs only if the condi- tion expression evaluates true. C and C++ programmers take note: unlike C and C++, in which any expression can be used in a conditional, C# requires that all condi- tional expressions evaluate to a Boolean value. if else statements if else statements branch based on a condition. The condition is an expression, tested in the head of the if statement. If the condition evaluates true, the statement (or block of statements) in the body of the if statement is executed. if statements may contain an optional else statement. The else statement is exe- cuted only if the expression in the head of the if statement evaluates false: if (expression) statement1 [else statement2] This is the kind of if statement description you are likely to find in your compiler documentation. It shows you that the if statement takes a Boolean expression (an expression that evaluates true or false) in parentheses, and executes statement1 if the expression evaluates true. Note that statement1 can actually be a block of statements within braces. You can also see that the else statement is optional, as it is enclosed in square brackets. Square brackets are used in the documentation to indicate that the expression is optional. Parentheses (in the if statement) are not part of the documentation, they are actually required in the code. Although this gives you the syntax of an if statement, an illustration will make its use clear. See Example 3-7. 36 | Chapter 3: C# Language Fundamentals In Example 3-7, the first if statement tests whether valueOne is greater than valueTwo. The relational operators such as greater than (>), less than (<), and equal to ( ==) are fairly intuitive to use. The test of whether valueOne is greater than valueTwo evaluates false (because valueOne is 10 and valueTwo is 20,sovalueOne is not greater than valueTwo). The else statement is invoked, printing the statement: ValueTwo: 20 is larger than ValueOne: 10 Example 3-7. if else statements using System; class Values { static void Main( ) { int valueOne = 10; int valueTwo = 20; if ( valueOne > valueTwo ) { Console.WriteLine( "ValueOne: {0} larger than ValueTwo: {1}", valueOne, valueTwo); } else { Console.WriteLine( "ValueTwo: {0} larger than ValueOne: {1}", valueTwo,valueOne); } valueOne = 30; // set valueOne higher if ( valueOne > valueTwo ) { valueTwo = valueOne + 1; Console.WriteLine("\nSetting valueTwo to valueOne value, "); Console.WriteLine("and incrementing ValueOne.\n"); Console.WriteLine("ValueOne: {0} ValueTwo: {1}", valueOne, valueTwo); } else { valueOne = valueTwo; Console.WriteLine("Setting them equal. "); Console.WriteLine("ValueOne: {0} ValueTwo: {1}", valueOne, valueTwo); } } } Statements | 37 The second if statement evaluates true and all the statements in the if block are evaluated, causing two lines to print: Setting valueTwo to valueOne value, and incrementing ValueOne. ValueOne: 31 ValueTwo: 30 Nested if statements It is possible, and not uncommon, to nest if statements to handle complex condi- tions. For example, suppose you need to write a program to evaluate the temperature, and specifically to return the following types of information: • If the temperature is 32 degrees or lower, the program should warn you about ice on the road. • If the temperature is exactly 32 degrees, the program should tell you that there may be ice patches. There are many good ways to write this program. Example 3-8 illustrates one approach, using nested if statements. Statement Blocks You can substitute a statement block anywhere that C# expects a statement. A statement block is a set of statements surrounded by braces. Thus, where you might write: if (someCondition) someStatement; you can instead write: if(someCondition) { statementOne; statementTwo; statementThree; } Example 3-8. Nested if statements using System; using System.Collections.Generic; using System.Text; namespace NestedIf { class NestedIf { 38 | Chapter 3: C# Language Fundamentals The logic of Example 3-8 is that it tests whether the temperature is less than or equal to 32. If so, it prints a warning: if (temp <= 32) { Console.WriteLine("Warning! Ice on road!"); The program then checks whether the temp is equal to 32 degrees. If so, it prints one message; if not, the temp must be less than 32, and the program prints the second message. Notice that this second if statement is nested within the first if, so the logic of the else is “since it has been established that the temp is less than or equal to 32, and it isn’t equal to 32, it must be less than 32.” switch statements: an alternative to nested ifs Nested if statements can be hard to read, hard to get right, and hard to debug when used to excess (do not operate heavy machinery when using more than six). When you have a complex set of choices to make, the switch statement may be a more readable alternative. The logic of a switch statement is “pick a matching value and act accordingly”: switch (expression) { case constant-expression: statement jump-statement [default: statement] } static void Main( ) { int temp = 32; if ( temp <= 32 ) { Console.WriteLine( "Warning! Ice on road!" ); if ( temp == 32 ) { Console.WriteLine( "Temp exactly freezing, beware of water." ); } else { Console.WriteLine( "Watch for black ice! Temp: {0}", temp ); } // end else } // end if (temp <= 32) } // end main } // end class } // end namespace Example 3-8. Nested if statements (continued) Statements | 39 As you can see, like an if statement, the expression is put in parentheses in the head of the switch statement. Each case statement then requires a constant expression; that is, a literal or symbolic constant or an enumeration. If a case is matched, the statement(s) associated with that case is executed. This must be followed by a jump statement. Typically, the jump statement is break, which transfers execution out of the switch. An alternative is a goto statement, typically used to jump into another case, as Example 3-9 illustrates. All Operators Aren’t Created Equal A closer examination of the second if statement in Example 3-8 reveals a common potential problem. This if statement tests whether the temperature is equal to 32: if (temp == 32) In C and C++, there is an inherent danger in this kind of statement. It’s not uncommon for novice programmers to use the assignment operator rather than the equals opera- tor, instead creating the statement: if (temp = 32) This mistake would be difficult to notice, and the result would be that 32 was assigned to temp, and 32 would be returned as the value of the assignment statement. Because any nonzero value evaluates true in C and C++ the if statement would return true. The side effect would be that temp would be assigned a value of 32 whether or not it origi- nally had that value. This is a common bug that could easily be overlooked—if the developers of C# had not anticipated it! C# solves this problem by requiring if statements to accept only Boolean values. The 32 returned by the assignment is not Boolean (it is an integer) and, in C#, there is no automatic conversion from 32 to true. Thus, this bug would be caught at compile time, which is a very good thing and a significant improvement over C++, at the small cost of not allowing implicit conversions from integers to Booleans! C++ programmers take note: because the buggy assignment statement will be caught at compile time, it is no longer necessary to use the counterintuitive syntax: if ( 32 == temp ) that was C++’s solution to this problem. Example 3-9. The switch statement using System; class SwitchStatement { enum Party { Democrat, ConservativeRepublican, Republican, Libertarian, Liberal, 40 | Chapter 3: C# Language Fundamentals In this whimsical example, we create constants for various political parties. We then assign one value ( Libertarian) to the variable myChoice and switch according to that value. If myChoice is equal to Democrat, we print out a statement. Notice that this case ends with break. break is a jump statement that takes us out of the switch statement and down to the first line after the switch, on which we print, “Thank you for voting.” VB 6 programmers take note: the equivalent of the C# switch state- ment is the VB 6 Select Case statement. Also, whereas VB 6 allows you to test a range of values using a single Case statement, C# syntax doesn’t provide for this contingency. The following two Case state- ments are syntactically correct in VB 6: Case Is > 100 Case 50 to 60 However, these statements aren’t valid in C#. In C#, you can test only a single constant expression. To test a range, you must test each value independently and “fall through” to a common case block. Progressive, }; static void Main(string[] args) { Party myChoice = Party.Libertarian; switch (myChoice) { case Party.Democrat: Console.WriteLine("You voted Democratic.\n"); break; case Party.ConservativeRepublican: // fall through //Console.WriteLine( //"Conservative Republicans are voting Republican\n"); case Party.Republican: Console.WriteLine("You voted Republican.\n"); break; case Party.Liberal: Console.WriteLine(" Liberal is now Progressive"); goto case Party.Progressive; case Party.Progressive: Console.WriteLine("You voted Progressive.\n"); break; case Party.Libertarian: Console.WriteLine("Libertarians are voting Democratic"); goto case Party.Democrat; default: Console.WriteLine("You did not pick a valid choice.\n"); break; } Console.WriteLine("Thank you for voting."); } } Example 3-9. The switch statement (continued) Statements | 41 The value ConservativeRepublican has no statement under it, and it “falls through” to the next statement: Republican. If the value is ConservativeRepublican or Republican, the Republican statements execute. You can “fall through” in this way only if there is no body within the statement. If you uncomment WriteLine( ) under LiberalRepublican, this program won’t compile. C and C++ programmers take note: you can’t fall through to the next case unless the case statement is empty. Thus, you can write this: case 1: // fall through ok (no statement for case 1) case 2: You can’t, however, write this: case 1: TakeSomeAction( ); // fall through not OK, case 1 not empty case 2: Here, case 1 has a statement in it, and you can’t fall through. If you want case 1 to fall through to case 2, you must explicitly use goto: case 1: TakeSomeAction( ); goto case 2; // explicit fall through case 2: If you do need a statement, but then you want to execute another case, you can use the goto statement as shown in the Liberal case: goto case Progressive; It is not required that the goto take you to the next case statement. For instance, in the next example, the Libertarian choice also has a goto, but this time it jumps all the way back up to the Democrat case. Because our value was set to Libertarian, this is just what occurs. We print out the Libertarian statement, go to the Democrat case, print that statement, and then hit the break, taking us out of the switch and down to the final statement. The output for all of this is: Libertarians are voting Democrat now. You voted Democrat. Thank you for voting. Note the default case, excerpted from Example 3-9: default: Console.WriteLine( "You did not pick a valid choice.\n"); If none of the cases match, the default case will be invoked, warning the user of the mistake. [...]... i2 ); } } } Output: Integer: float: double: decimal: 4 4.25 4.25 4.25 Modulus: 1 Operators | 51 Now, consider this line from Example 3-16: Console.WriteLine("Integer:\t{0}\nfloat:\t\t{1}", i1/i2, f1/f2); It begins with a call to Console.WriteLine( ), passing in this partial string: "Integer:\t{0}\n This will print the characters Integer: followed by a tab (\t), followed by the first parameter ({0}),... prints float: followed by two tabs (to ensure alignment), the contents of the second parameter ({1}), and then another newline Notice the subsequent line, as well: Console.WriteLine("\nModulus:\t{0}", i1%i2); This time, the string begins with a newline character, which causes a line to be skipped just before the string Modulus: is printed You can see this effect in the output Increment and Decrement Operators... 3; Operators | 55 there are three operators for the compiler to evaluate (=, +, and *) It could, for example, operate left to right, which would assign the value 5 to myVariable, then add 7 to the 5 ( 12) and multiply by 3 (36)—but, of course, then it would throw that 36 away This is clearly not what is intended The rules of precedence tell the compiler which operators to evaluate first As is the case . whether the temperature is less than or equal to 32. If so, it prints a warning: if (temp <= 32) { Console.WriteLine("Warning! Ice on road!"); The program then checks whether the. Console.WriteLine( "Watch for black ice! Temp: {0}", temp ); } // end else } // end if (temp <= 32) } // end main } // end class } // end namespace Example 3-8. Nested if statements (continued) Statements | 39 As. common potential problem. This if statement tests whether the temperature is equal to 32: if (temp == 32) In C and C++, there is an inherent danger in this kind of statement. It’s not uncommon for novice