Chapter 7: Program Control Statements


Program control statements tell an application which other statements to execute under a particular set of circumstances. They control the path that execution takes through the code. They include commands that tell the program to execute some statements but not others and to execute certain statements repeatedly.

The two main categories of control statements are decision (or conditional) statements and looping statements. The following sections describe in detail the decision and looping statements provided by Visual Basic .NET.

Decision Statements

A decision or conditional statement represents a branch in the program. It marks a place where the program can execute one set of statements or another, or possibly no statements at all, depending on some condition. These include If, Choose, and Select Case statements.

Single Line If Then

The single-line If Then statement has two forms. The first allows the program to execute a single statement if some condition is true. The syntax is as follows:

  If condition Then statement 

If the condition is true, the program executes the statement. In the most common form of single-line If Then statement, the statement is a single simple command (such as assigning a value to a variable or calling a subroutine).

The following example checks the emp object’s IsManager property. If IsManager is True, the statement sets the emp object’s Salary property to 90,000.

  If emp.IsManager Then emp.Salary = 90000 

The other variations on the single-line If Then statement are more confusing and generally harder to debug and maintain. To prevent unnecessary confusion, many programmers switch to the multiline If Then statement described in the next section when the simple single-statement version won’t work.

The second form of single-line If Then statement uses the Else keyword. The syntax is as follows:

  If condition Then statement1 Else statement2 

If the condition is true, the code executes the first statement. If the condition is false, the code executes the second statement. The decision about which statement to execute is an either-or decision; the code executes one statement or the other, but not both.

This type of single-line If Then Else statement is very confusing if it is too long to easily see in the code editor. For longer statements, a multiline If Then Else statement is easier to understand and debug. The performance of single-line and multiline If Then Else statements is comparable (in one test, the multiline version took only about 80 percent as long), so you should use the one that seems easiest for you to read.

The statements executed by a single-line If Then statement can be simple commands (such as assigning a value to a variable). They can also be a series of simple statements separated by colons on the same line. For example, the following code tests the value of the Boolean variable is_new_customer. If is_new_customer is true, the program calls the customer object’s Initialize method and then calls its Welcome method.

  If is_new_customer Then customer.Initialize() : customer.Welcome() 

Using more than one simple statement separated by colons like this can be perplexing. It gets even worse if you use single-line If Then Else, as shown here:

  If order.Valid() Then order.Save() : order.Post() Else order.order.Delete() 

The single-line If Then statement can also include Else If clauses. For example, the following code examines the variable X. If X is 1, the program displays a message box saying “One.” If X has the value 2, the program displays a message box saying “Two.” If X is not 1 or 2, the program displays a message box containing a question mark.

  If X = 1 Then MsgBox("One") Else If X = 2 Then MsgBox("Two") Else MsgBox("?") 

The code can include as many Else If clauses as you like, and each execution statement can be composed of multiple simple statements separated by colons. However, confusing code such as these examples can lead to puzzling bugs that are easy to avoid if you use multiline If Then statements instead.

In summary, if you can write a simple single-line If Then statement with no Else If or Else clauses, and the whole thing fits nicely on the line so that it’s easy to see the whole thing without confusion, go ahead. If the statement is too long to read easily, contains Else If or Else clauses, or executes a series of statements separated by colons, you are usually better off using a multiline If Then statement. It may take more lines of code, but the code will be easier to read, debug, and maintain later.

Multiline If Then

A multiline If Then statement can execute more than one line of code when a condition is true. The syntax for the simplest form of multiline If Then statement is as follows:

  If condition Then     statements... End If 

If the condition is true, the program executes all the commands that come before the End If statement. For example, the following code shows a multiline version of one of the statements shown in the previous section. If the Boolean variable is_new_customer has value True, the program calls the customer object’s Initialize method and then calls its Welcome method.

  If is_new_customer Then     customer.Initialize()     customer.Welcome() End If 

Like the single-line If Then statement, the multiline version can include Else If and Else clauses. For possibly historical reasons, ElseIf is spelled as a single word in the multiline If Then statement. The syntax is as follows:

  If condition1 Then     statements1... ElseIf condition2     statements2... Else     statements3... End If 

If the first condition is true, the program executes the first set of statements. If the first condition is false, the code examines the second condition and, if that one is true, the code executes the second set of statements. The program continues checking conditions until it finds one that is true and it executes the corresponding code.

If the program reaches an Else statement, it executes the corresponding code. If the program reaches the End If statement without finding a true condition or an Else clause, it doesn’t execute any of the statement blocks.

The following simple example shows a multiline version of the confusing single-line If Then Else statement shown in the section “Single Line If Then” earlier in this chapter.

  If order.Valid() Then     order.Save()     order.Post() Else     order.Reject()     order.Delete() End If 

It is important to understand that the program exits the If Then construction immediately after it has executed the block of statements that goes with the first condition it finds that is true. It does not examine the other conditions. This saves the program some time and is particularly important if the conditions involve functions. If each test calls a relatively slow function, skipping these later tests can save the program a significant amount of time.

You need to be particularly aware of this issue if the conditions call functions that have side effects. A side effect is some change in the program’s state that can affect parts of the program outside of the function. If you don’t know how many of an If Then statement’s conditions are executed, you cannot know which side effects may have occurred.

For example, suppose the GetEmployee function pulls data from a database to initialize an Employee object and returns that object. The following code loads Alice Adams’ record and checks to see if she is a manager. If Alice is not a manager, the code loads Brian Buckley’s data and sees if he is a manager. If Brian isn’t a manager either, the code checks Cindy Cantrell and possibly others.

  If GetEmployee("Alice Adams").IsManager() Then     ... ElseIf GetEmployee("Brian Buckley").IsManager() Then     ... ElseIf GetEmployee("Cindy Cantrell").IsManager() Then     ... ElseIf ...     ... End If 

After this code finishes executing, how many Employee objects has the program loaded? Are all of the employees loaded, or are some still only in the database? The answers depend on which of these people is a manager. If Alice is a manager, the program loads only her record. If none of these people is a manager, the program loads data for everyone. If someone later in the list is a manager, the program loads some but not all of the employees. There’s no easy way to tell how many Employee objects were created without knowing all the details contained in the employee data.

In this example, knowing the number of employees loaded might not be big deal. However, whenever an If Then statement uses a series of conditions with side effects, you cannot easily tell what state the program is in afterward.

You can avoid this type of potential confusion by not using routines with side effects in this sort of If Then structure. One alternative would be to load every employee and then look for one who is a manager. In this example, that may take a little longer if Alice Adams is a manager, but at least the program is in a well-known state afterwards.

Select Case

The Select Case statement lets a program execute one of several pieces of code depending on a single value. The basic syntax is as follows:

  Select Case test_value     Case comparison_expression1         statements1     Case  comparison_expression2         statements2     Case  comparison_expression3         statements3     ...     Case Else         else_statements End Select  

If test_value matches comparison_expression1, the program executes the statements in the block statements1. If test_value matches comparison_expression2, the program executes the statements in the block statements2. The program continues checking the expressions in the Case statements in order until it matches one, or it runs out of Case statements.

If test_value doesn’t match any of the expressions in the Case statements, the program executes the code in the else_statements block. Note that you can omit the Case Else section. In that case, the program executes no code if test_value doesn’t match any of the expressions.

For example, the following code checks the value in the txtDessertSelection text box and displays a message. If the text box doesn’t contain one of the strings Pie, Cake, or Cookies, the code displays the message “You have not selected a dessert.”

  Select Case txtDessertSelection.Text     Case "Pie"         MessageBox.Show("You have selected pie")     Case "Cake"         MessageBox.Show("You have selected cake")     Case "Cookies"         MessageBox.Show("You have selected cookies")     Case Else         MessageBox.Show("You have not selected a dessert") End Select  

Select Case is functionally equivalent to an If Then Else statement. The following code does the same thing as the previous version:

  If txtDessertSelection.Text = "Pie" Then     MessageBox.Show("You have selected pie") ElseIf txtDessertSelection.Text = "Cake" Then     MessageBox.Show("You have selected cake") ElseIf txtDessertSelection.Text = "Cookies" Then     MessageBox.Show("You have selected cookies") Else     MessageBox.Show("You have not selected a dessert") End If  

Select Case is sometimes easier to understand than a long If Then Else statement. It is often faster as well, largely because Select Case doesn’t need to reevaluate test_value for every Case statement. In the previous code, each ElseIf clause must find the value of txtDessertSelection.Text. The Select Case version only calculates this value once, and then compares the result to the comparison expressions in the Case statements. The savings in time can be significant in frequently executed code when test_value is extremely complicated. For example, in the following code, the test expression accesses a deeply nested series of object properties. Reevaluating this expression for each ElseIf statement would take a relatively long time.

  If employee.Department.Manager.Secretary. _   HomeAddress.Phone.SubString(0, 3) = "212" Then     ... ElseIf employee.Department.Manager.Secretary. _   HomeAddress.Phone.SubString(0, 3) = "213" Then     ... ElseIf employee.Department.Manager.Secretary. _   HomeAddress.Phone.SubString(0, 3) = "214" Then     ... End If 

If you think a particular piece of code will be easier to understand using an If Then Else statement instead of a Select Case statement, you can speed the code up (and make it easier to read) by storing a complex test_value in a variable. The following code shows an improved version of the previous

  Dim phone_prefix As String = employee.Department.Manager.Secretary. _     HomeAddress.Phone.SubString(0, 3) = "123" If phone_prefix = "212" Then     ... ElseIf phone_prefix = "213" Then     ... ElseIf phone_prefix = "214" Then     ... End If 

The comparison expressions used in a Select Case statement are often constants. In the earlier examples, the expressions are the constant strings Pie, Cake, and Cookies. A comparison expression can also specify ranges using the To and Is keywords, and include a comma-separated list of expressions. These forms are described in the following sections. The final section describing Select Case discusses using enumerated values to control Select Case statements.

To

The To keyword specifies a range of values that test_value should match. The following code examines the variable num_items. If num_items is between 1 and 10, the program calls subroutine ProcessSmallOrder. If num_items is between 11 and 100, the program calls subroutine ProcessLargeOrder. If num_items is less than 1 or greater than 100, the program beeps.

  Select Case num_items     Case 1 To 10         ProcessSmallOrder()     Case 11 To 100         ProcessLargeOrder()     Case Else         Beep() End Select 

Is

The Is keyword lets you perform comparisons using num_items. The word Is takes the place of num_items in a comparison expression. For example, the following code does almost the same things as the previous version. If the value num_items is less than or equal to 10, the program calls subroutine ProcessSmallOrder. If the first Case clause doesn’t apply and num_items is less than or equal to 100, the program calls subroutine ProcessLargeOrder. If neither of these cases applies, the program beeps.

  Select Case num_items     Case Is <= 10         ProcessSmallOrder()     Case Is <= 100         ProcessLargeOrder()     Case Else         Beep() End Select  

This version is slightly different from the previous one. If num_items is less than 1, this code calls subroutine ProcessSmallOrder while the previous version beeps.

Note also that the order of the Case clauses is important in this example. If you were to reverse the first two Case clauses, ProcessSmallOrder would never be used. Any value less than or equal to 10 is also less than or equal to 100, so any value that would satisfy the case Is <= 10 would be handled by the case Is <= 100 before the program reached the second Case clause.

You can use the operators =, <>, <, <=, >, and >= in an Is clause. (In fact, if you use a simple value in a Case clause as in Case 7, you are implicitly using Is = as in CaseIs=7.)

Comma-Separated Expressions

A comparison expression can include a series of expressions separated by commas. If the test value matches any of the comparison values, the program executes the corresponding code.

For example, the following code examines the department_name variable. If department_name is R&D, Test, or Computer Operations, the code adds the text Building 10 to the address_text string. If department_name is Finance, Purchasing, or Accounting, the code adds Building 7 to the address. More Case clauses could check for other department_name values and the code could include an Else statement.

  Select Case department_name     Case "R & D", "Test", "Computer Operations"         address_text &= "Building 10"     Case "Finance", "Purchasing", "Accounting"         address_text &= "Building 7"     ... End Select 

Note that you cannot use comma-separated expressions in a Case Else clause. For example, the following code doesn’t work:

  Case Else, "Corporate"     ' This doesn't work. 

However, you can simply omit any values you want to use with the Else clause. If the values don’t appear in another Case clause, the program will execute the Else clause code when it finds those values. You can make the code more self-documenting by including the comparison values in a comment after the Else keyword, as in the following statement:

  Case Else    ' Corporate 

You can mix and match constants, To, and Is expressions in a single Case clause, as shown in the following example. This code checks the variable item_code and calls subroutine DoSomething if the value is less than 10, between 30 and 40 inclusive, exactly equal to 100, or greater than 200.

  Select Case item_code     Case Is < 10, 30 To 40, 100, Is > 200         DoSomething() End Select  

Complex comparison expressions are sometimes difficult to read. If an expression is too complicated, you should consider rewriting the code to make it easier to understand. Storing values in temporary variables can help.

Enumerated Values

Select Case statements work very naturally with lists of discrete values. You can have a separate Case statement for each value, or you can list multiple values for one Case statement in a comma-separated list.

Enumerated types defined by the Enum statement also work with discrete value, so they work well with Select Case statements. The enumerated type defines the values and the Select Case statement uses them, as shown in the following code fragment:

  Private Enum JobStates     Pending     Assigned     InProgress     ReadyToTest     Tested     Released End Enum Private m_JobState As JobStates ... Select Case m_JobState     Case Pending         ...     Case Assigned         ...     Case InProgress         ...     Case ReadyToTest         ...     Case Tested         ...     Case Released         ... End Select  

To catch bugs when changing an enumerated type, many developers include a Case Else statement that throws an exception. If you later add a new value to the enumerated type, the Select Case statement throws an error when it sees it, so you can modify the code to handle the new value.

For more information on enumerated types, see the section “Enumerated Data Types” in Chapter 4.

IIf

The IIf statement evaluates a Boolean expression and then returns one of two values, depending on whether the expression is true or false. This statement may look more like an assignment statement or a function call than a decision statement such as If Then.

The syntax is as follows:

  variable = IIf(condition, value_if_true, value_if_false) 

For example, the following code examines an Employee object’s IsManager property. If IsManager is True, the code sets the employee’s Salary to 90,000. If IsManager is False, the code sets the employee’s Salary to 10,000.

  emp.Salary = IIf(emp.IsManager, 90000, 10000) 

Note that the IIf statement returns an Object data type. If you have Option Strict turned on, Visual Basic will not allow this statement, because it assigns a result of type Object to an Integer variable. To satisfy Visual Basic, you must explicitly convert the value into an Integer, as in the following code:

  emp.Salary = CInt(IIf(emp.IsManager, 90000, 10000)) 

The IIf statement has several drawbacks. First, it is confusing. When you type an IIf statement, IntelliSense will remind you that its parameters give a condition, a true value, and a false value. When you are reading the code, however, you must remember what the different parts of the statement mean. If you use IIf in some other statement, the chances for confusion increase. For example, consider the following code:

  For i = 1 To CType(IIf(employees_loaded, num_employees, 0), Integer)     ' Process employee i.     ... Next i  

Code is generally much easier to understand if you replace IIf with an appropriate If Then statement. The following code takes more lines of code but is easier to understand than the previous version:

  If employees_loaded Then     max_i = num_employees Else     max_i = 0 End If For i = 1 To max_i     ' Process employee i.     ... Next i  

Another drawback to IIf is that it evaluates both the true and false values whether the condition is true or false. For example, consider the following code. If the Boolean use_groups is True, the code sets num_objects to the result of the CountGroups function. If use_groups is False, the code sets num_objects to the result of the CountIndividuals function. IIf evaluates both functions no matter which value it actually needs. If the functions are time-consuming or executed inside a large loop, this can waste a lot of time.

  num_objects = CType(IIf(use_groups, CountGroups(), CountIndividuals()), Integer) 

For an even more dangerous example, consider the following code. If data_loaded is True, this statement sets num_loaded = num_employees. If data_loaded is False, the code sets num_loaded to the value returned by the LoadEmployees function (which loads the employees and returns the number of employees it loaded).

  num_loaded = CType(IIf(data_loaded, num_employees, LoadEmployees()), Integer) 

IIf evaluates both the value num_employees and the value LoadEmployees() no matter what. If the employees are already loaded, IIf calls LoadEmployees() to load the employees again, ignores the returned result, and sets num_loaded = num_employees. LoadEmployees may waste quite a while loading the data that is already loaded. Even worse, the program may not be able to handle loading the data when it is already loaded.

A final drawback to IIf is that it is slower than a comparable If Then Else statement. In one test, IIf took roughly twice as long as a comparable If Then statement.

One case where you can argue that IIf is easier to understand is when you have a long series of very simple statements. In that case, IIf statements may allow you to easily see the common features in the code and notice if anything looks wrong. For example, the following code initializes several text boxes using strings. It uses an IIf statement to set a text box’s value to <Missing> if the string is not yet initialized.

  txtLastName.Text = IIf(last_name Is Nothing, "<Missing>", last_name) txtFirstName.Text = IIf(first_name Is Nothing, "<Missing>", first_name) txtStreet.Text = IIf(street Is Nothing, "<Missing>", street) txtCity.Text = IIf(city Is Nothing, "<Missing>", city) txtState.Text = IIf(state Is Nothing, "<Missing>", state) txtZip.Text = IIf(zip Is Nothing, "<Missing>", zip) 

The following code uses If Then statements to avoid the IIf statements. This version is a bit more difficult to read, partly because it is much longer.

  If last_name Is Nothing Then     txtLastName.Text = "<Missing>" Else     txtLastName.Text = last_name End If If first_name Is Nothing Then     txtFirstName.Text = "<Missing>" Else     txtFirstName.Text = first_name End If If street Is Nothing Then     txtStreet.Text = "<Missing>" Else     txtStreet.Text = street End If If city Is Nothing Then     txtCity.Text = "<Missing>" Else     txtCity.Text = city End If If state Is Nothing Then     txtState.Text = "<Missing>" Else     txtState.Text = state End If If zip Is Nothing Then     txtZip.Text = "<Missing>" Else     txtZip.Text = zip End If  

In larger programming projects, debugging and maintenance are much bigger costs than development. Use IIf only if it makes the code easier to understand.

Choose

The IIf statement uses a Boolean expression to pick between two values. The Choose statement uses an integer to decide among any number of options. The syntax is as follows:

  variable = Choose(index, value1, value2, value3, value4, ...) 

If the index parameter is 1, Choose returns the first value, value1; if index is 2, Choose returns value2; and so forth. If index is less than 1 or greater than the number of values in the parameter list, Choose returns Nothing.

This statement has the same drawbacks as IIf. Sometimes Choose is more confusing than a comparable Select Case statement. If the values look dissimilar (mixing integers, objects, function calls, and so forth), involve complicated functions, or are wrapped across multiple lines, a Select Case statement may be easier to read.

However, if the Choose statement’s values are short and easy to understand, and the statement contains many values, the Choose statement may be easier to read. For example, the following Choose and Select Case statements do the same thing. Because the Choose statement’s values are short and easy to understand, this statement is easy to read. The Select Case statement is rather long. If the program had more choices, the Select Case statement would be even longer, making it more difficult to read.

  fruit = Choose(index, "apple", "banana", "cherry", "date") Select Case index     Case 1         fruit = "apple"     Case 2         fruit = "banana"     Case 3         fruit = "cherry"     Case 4         fruit = "date" End Select  

While it’s not always clear whether a Choose statement or a Select Case statement will be easier to read, Select Case is certainly faster. In one test, Choose took more than five times as long as Select Case.If the code lies inside a frequently executed loop, the speed difference may be an issue.

Choose and Select Case are not your only options. You can also store the program’s choices in an array, and then use the index to pick an item from the array. For example, the following code stores the strings from the previous example in the values array. It then uses the index to pick the right choice from the array.

  Dim values() As String = {"apple", "banana", "cherry", "date"} fruit = values(index - 1) 

Notice that the code subtracts 1 from the index when using it to pick the right choice. The Choose statement indexes its values starting with 1, but arrays in Visual Basic .NET start with index 0. Subtracting 1 allows the program to use the same index values used in the previous example.

This version makes you think about the code in a different way. It requires that you know that the values array contains the names of the fruits that the program needs. If you understand the array’s purpose, then the assignment statement is easy to understand.

The assignment code is even slightly faster than Select Case, at least if you can initialize the values array ahead of time.

If you find Choose easy to understand and it doesn’t make your code more difficult to read in your particular circumstances, by all means use it. If Select Case seems clearer, use that. If you will need to perform the assignment many times and pre-building an array of values makes sense, using a value array might improve your performance.




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

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