One goal of this book is for you to pick up the language fundamentals of Visual Basic 2005 as you create applications. Thus, Chapter 1 starts right off with building applications and eschews the traditional introduction to programming elements such as If
statements, While
loops, and so forth.
That said, Visual Basic 2005 is a full programming language with its own complexities. This chapter is aimed at readers who would like to get the fundamentals under their belt before reading the rest of the book (feel free to read this chapter first), or readers who want to review the fundamentals after reading the book, as well as readers who want to dip in now and then, to check how certain things are done as they read the book.
While this book is aimed at VB6 programmers making the transition to .NET, this chapter does not assume prior experience with Visual Basic or any other programming language, though if you’ve never programmed at all you may find the pace a bit quick.
Every object in Visual Basic 2005 has a type. Types come in two flavors:
Visual Basic 2005 offers a number of intrinsic types , as shown in Table 16-1.
Type |
Size (in bytes) |
.NET type |
Description |
|
1 |
|
|
|
1 |
|
Unsigned (values |
|
2 |
|
Unicode characters. |
|
8 |
|
|
|
12 |
|
Fixed-precision up to 28 digits and the position of the decimal point. This is typically used in financial calculations. Requires the suffix “m” or “M.” |
|
8 |
|
Double-precision floating-point; holds the values from approximately +/−5.0 * 10−324 to approximate +/−1.8 * 10308 with 15–16 significant figures. |
|
4 |
|
Integer values between -2,147,483,648 and 2,147,483,647. |
|
8 |
|
Integers ranging from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. |
|
2 |
|
Integer values -32,768 to 32,767 |
|
4 |
|
Floating-point number. Holds the values from approximately+/-1.5 * 10-45 to approximate +/-3.4 * 1038 with 7 significant figures. |
|
|
|
A sequence of Unicode characters. |
Each type has a name (e.g., Integer
) and a size (e.g., 4 bytes) The size tells you how many bytes each object of this type occupies in memory. Programmers generally don’t like to waste memory if they can avoid it, but with the cost of memory these days, you can afford to be mildly profligate if doing so simplifies your program.
Each Visual Basic 2005 type corresponds to an underlying .NET type. Thus, what Visual Basic 2005 calls an Integer
, .NET calls an Int32
. This is interesting only if you care about sharing objects across languages, an important topic but one that is beyond the scope of this book. The description field of Table 16-1 tells you the minimum and maximum values you can hold in objects of each type.
Most of the intrinsic types are used for working with numeric
values (Byte
, Short
, Integer
, Single
, Double
, Decimal
, Long
).
Another way to divide the types is into those used for integer (whole number) values, and those used for fractional values. The Short
, Integer
, and Long
types all hold whole number values. Most of the time, you’ll just use Integer
for these values, unless there is a good reason to do otherwise.
The Single
and Double
types hold fractional values (rational numbers). For most uses, Single
will suffice, unless you need to hold a really big fractional number, in which case you might use a Double
. The Decimal
value type was added to the language to support accounting applications, and is described in Table 16-1.
In addition to the numeric types, the Visual Basic 2005 language offers four other primitive types: Char
, String
, Date
, and Boolean
.
The Char
type is used from time to time when you need to hold a single character. For sequences of characters you’ll use the String
type. Date types are used to hold date and time values, and are most useful when working with databases from which you might extract a date-time value.
The one remaining type of importance is Boolean
. A Boolean
value is a value that is either True
or False
.
When you create a program under Visual Basic 2005, you may choose to set Option Explicit
and Option Strict
to On
, by writing these lines at the top of your source code:
Option Strict On Option Explicit On
If you use Option Explicit or Option Strict, you must make them the first statements in your source code file.
Option Explicit
requires that every variable be declared before it is used (variables are explained in the next section). Option Strict
restricts the way you cast from one type to another. Both enable the compiler to help you find bugs in your program and together they make Visual Basic 2005 a strongly typed language; and that is a very good thing. This book assumes you will always set both Option Explicit
and Option Strict
on.
In a strongly typed language, every object you create or use must have a specific type (e.g., you must declare the object to be an Integer
, a String,
or a Dog
). The type tells the compiler how big the object is and what it can do.
Confusingly, a perfectly legitimate type is type Object, though this type is rarely used and tends to undermine type safety.
The size of an object is measured in bytes. An Integer
, for example, is four bytes big. User-defined types have a size as well, measured as the sum of all their member variables.
When programmers talk about what an object can do, they typically mean the methods of the object. User-defined types have many methods. Intrinsic types have implicit methods. For example, the numeric types have the ability to be added together, multiplied, and so forth.
The compiler will help you by complaining if you try to use a type improperly. The compiler complains in one of two ways: it issues a warning or it issues an error.
You are well advised to treat warnings as errors. That is, you ought to stop what you are doing and figure out why there is a warning and fix the problem. Never ignore a compiler warning.
Programmers talk about “design time,” “compile time,” and runtime.” Design time is when you are designing the program. Compile time is when you compile the program, and runtime is (surprise!) when you run the program.
The earlier you find a bug, the better. It is best (and cheapest) to discover a bug in your logic at design time. It is better (and cheaper) to find bugs in your program at compile time rather than at runtime. Not only is it better, it is more reliable. A compile-time bug will fail every time you run the compiler, but a runtime bug can hide. Runtime bugs slip under a crack in your code, and lurk there (sometimes for months) biding their time, waiting to come out when it will be embarrassing to you.
It is a constant theme of this book that you want the compiler to find bugs. The compiler is your friend. The more bugs the compiler finds, the fewer bugs your users will find. Setting Option Strict On
helps the compiler find bugs in your code. Here’s how: suppose you tell the compiler that Milo is of type Dog
. Some time later you try to use Milo to display text. Oops, Dog
objects don’t display text. Your compiler will stop with an error.
Dog does not contain a definition for 'showText'
Very nice. Now you can go figure out if you used the wrong object or you called the wrong method.
Visual Studio 2005 actually finds the error even before the compiler does. When you try to add a method that does exist, IntelliSense pops up to help you, as shown in Figure 16-1.
When you try to add a method that does not exist, it won’t be in the list. That is a pretty good clue that you are not using the object properly.
A variable is an object that holds a value:
Dim myVariable as Integer = 15
In this example, myVariable
is an object of type Integer
. It has been initialized with the value 15
. The formal definition for how you create a variable is:
Access-Modifier Identifier
AsType
[=value
]
Access modifiers are discussed later in this chapter; for now, you’ll use Dim
.
The keyword Dim
is short for dimension. This term dates back to the early days of BASIC programming, and is essentially vestigial.
An identifier is just a name for a variable, method, class, and so forth. In the case shown previously, the variable’s identifier is myVariable
. The keyword As
signals that what follows is the type, in this case Integer
. If you are initializing the variable, you follow the type with the assignment operators (=) followed by the value (e.g., 15
)
Variable identifiers may have a type character suffix that indicates the variable’s type. For example, rather than writing as Integer
you can use the suffix %
.
Dim myVariable as Integer Dim myVariable%
These two lines are identical in effect. Not every type is a character, but you are free to use them for those types that do. The complete set is shown in Table 16-2.
You are not required to initialize variables. You could write:
Dim myVariable as Integer
You can then assign a value to myVariable
later in your program:
Dim myVariable as Integer 'some other code here myVariable = 15 'assign 15 to myVariable
You can also change the value of a variable later in the program. That is why they’re called variables, their values vary.
Dim myVariable as Integer 'some other code here myVariable = 15 'assign 15 to myVariable 'some other code here myVariable = 12 'now it is 12
Technically, a variable is a named storage location with a type. The value 12
is being stored in the named location. You can safely think of a variable as being an object of the type specified. You can assign values to that object and then you can extract those values later.
The use of variables is illustrated in Example 16-1. To test this program, open Visual Studio 2005 and create a Console application. Type in the code as shown.
Here, we initialize the variable myInt
to the value 7
, display that value, reassign the variable with the value 5
, and display it again. To display the value we call the shared WriteLine
method on the console class (see the sidebar "WriteLine“).
Visual Basic 2005 does not require that you initialize your variables (though it is a very good idea to discipline yourself to do so). If you do not initialize your variable, it will be set to a default value, as shown in Table 16-3.
Variables are a powerful tool, but there are times when you want to manipulate a defined value, one whose value you want to ensure remains constant. For example, you might need to work with the Fahrenheit freezing and boiling points of water in a program simulating a chemistry experiment. Your program will be clearer if you name the variables that store these values FreezingPoint
and BoilingPoint
, but you do not want to permit their values to be reassigned. How do you prevent reassignment? The answer is to use a constant. A constant is like a variable except that its value cannot be changed once it is initialized.
A constant associates a name with a value, but you cannot change that value while the program runs. Hence, rather than varying, a constant is, well, constant.
Constants come in three flavors: literals , symbolic constants , and enumerations.
A literal constant is just a value, such as 32
. It does not have a name, it is just a literal value. And you can’t make the value 32
represent any other value. The value of 32
is always 32
. You can’t assign a new value to 32
; and you can’t make 32
represent the value 99
no matter how you might try.
When you write an integer as a literal constant, you are free just to write the number. The characters 32
are, together, a literal constant for the Integer
value 32
, and you can assign them accordingly:
Dim myValue as Integer = 32 'assign the literal value 32 to the variable myValue
If you want to assign a different type, however, you will want to use the correct format. For example, to designate the value 32
as a Double
(rather than as an Integer
) you will append the character R:
Dim myValue as Double = 32R 'assign literal value 32 as a Double
The complete list of literal formats is shown in Table 16-4.
Type |
Literal |
Example |
|
|
|
|
|
|
|
|
|
|
Any floating-point number, or |
|
|
Any integer value in range, or |
|
|
Any integer value outside the range of type Integer, or |
|
|
|
|
|
|
|
|
|
|
Symbolic constants assign a name to a constant value. You declare a symbolic
constant using the Const
keyword and the following syntax:
access-modifier
Constidentifier
astype = value
;
Access modifiers are discussed later; for now, you will use Public
.
The keyword Const
is followed by an identifier (the name of the constant), the keyword As
and the type of the constant (e.g., Integer
). This is similar to declaring a variable, except that you add the keyword Const
, and symbolic constants
must be initialized. Once initialized, a symbolic constant cannot be altered. For example:
Public Const FreezingPoint As Integer = 32
In this declaration, 32
is a literal constant and FreezingPoint
is a symbolic constant of type Integer
. Example 16-2 illustrates the use of symbolic constants.
Sub Main()
Const FreezingPoint As Integer = 32 ' degrees Farenheit
Const BoilingPoint As Integer = 212
Console.WriteLine("Freezing point of water: {0}", FreezingPoint)
Console.WriteLine("Boiling point of water: {0}", BoilingPoint)
'FreezingPoint = 0
End Sub
End Module
Example 16-2 creates two symbolic integer constants: FreezingPoint
and BoilingPoint
. See the sidebar "Naming Conventions" for symbolic constants.
These constants serve the same purpose as always using the literal values 32
and 212
for the freezing and boiling points of water in expressions that require them, but because these constants have names, they convey far more meaning. Also, if you decide to switch this program to Celsius, you can reinitialize these constants at compile time, to 0
and 100
, respectively; and all the rest of the code ought to continue to work.
To prove to yourself that the constant cannot be reassigned, try uncommenting the last line of the program (shown in bold). When you recompile, you should receive this error:
Constant cannot be the target of an assignment
Enumerations provide a powerful alternative to constants . An enumeration is a distinct value type, consisting of a set of named constants (called the enumerator list).
If you created two related constants:
Const FreezingPoint As Integer = 32 Const BoilingPoint As Integer = 212
you might wish to add a number of other useful constants as well, such as:
const LightJacketWeather As Integer = 60; const SwimmingWeather As Integer = 72; const WickedCold As Integer = 0;
This process is somewhat cumbersome, and there is no logical connection among these various constants. Visual Basic 2005 provides the enumeration to solve these problems:
Enum Temperatures CelsiusMeetsFahrenheit = −40 WickedCold = 0 FreezingPoint = 32 LightJacketWeather = 60 SwimmingWeather = 72 BoilingPoint = 212 End Enum
Every enumeration has an underlying type, which can be any integral type (Byte
, Short
, Integer
, and Long
). The technical specification of an enumeration is:
[accessmodifiers
]Enum
identifier
[Astype
] membername [ = constant expression] end Enum
In a specification statement like this, anything in square brackets is optional. That is, you can declare an Enum
with no base type. The base type is optional, even if Strict
is On
, and if you don’t define a base type, integer is assumed.
For now, let’s focus on the rest of this declaration. An enumeration begins with the keyword Enum
, which is followed by an identifier, such as:
Enum Temperatures
The AS keyword defines the underlying type for the enumeration. That is, are you declaring constant Integer
s, or constant Long
s? If you leave out this optional keyword (and often you will) the underlying type will be integer.
Example 16-3 rewrites Example 16-2 to use an enumeration.
Enum Temperatures WickedCold = 0 FreezingPoint = 32 LightJacketWeather = 60 SwimmingWeather = 72 BoilingPoint = 212 End Enum 'Temperatures Sub Main() System.Console.WriteLine( _ "Freezing point of water: {0}", _ Temperatures.FreezingPoint) System.Console.WriteLine( _ "Boiling point of water: {0}", _ Temperatures.BoilingPoint) End Sub End Module Output: Freezing point of water: FreezingPoint Boiling point of water: BoilingPoint
In Example 16-3, you declare enumerated constant Temperatures
. Temperatures
is an enumeration. The values of the enumeration must be qualified by the enumeration type. That means you cannot just refer to FreezingPoint
, but you must use the prefix Temperatures
followed by the dot operator. This is called qualifying the identifier FreezingPoint
. Thus, to refer to the FreezingPoint
you use the full identifier Temperatures.FreezingPoint
.
Unfortunately, if you pass the name of an enumeration to WriteLine
what is displayed is its name, not its value. To display the value of an enumerated constant, you must cast the constant to its underlying type (Integer
), as shown in Example 16-4.
Sub Main() System.Console.WriteLine( _ "Freezing point of water: {0}", _ CInt(Temperatures.FreezingPoint)) System.Console.WriteLine( _ "Boiling point of water: {0}", _ CInt(Temperatures.BoilingPoint)) End Sub End Module
When you cast a value (in this case, using the CInt
function), you tell the compiler, “I know that this value is really of the indicated type.” In this case, you are saying, “Treat this enumerated constant as an Integer.” Since the underlying type is Integer
, this is safe to do. See the section "Casting.”
Objects of one type can be converted into objects of another type. This is called casting , and casting can be either narrowing or widening.
A widening conversion or cast is one in which the conversion is to a type that can accommodate every possible value in the existing variable type. For example, an Integer
can accommodate every possible value held by a Short
. Casting from Short
to Integer
is, thus, a widening conversion.
A narrowing cast is one in which the conversion is to a type that may not be able to accommodate every possible value in the existing variable type. For example, a Short
can accommodate only some of the values that an Integer
variable might hold. Casting from an Integer
to a Short
is thus a narrowing conversion.
Visual Basic 2005 conversions are either implicit or explicit. In an implicit conversion, the compiler makes the conversion, with no special action by the developer. With an explicit conversion, the developer must use a special function to signal the cast. For example, in Example 16-4 you use the Cint
function to explicitly cast the enumerated value to an Integer.
The semantics of an explicit conversion are “Hey! Compiler! I know what I’m doing.” This is sometimes called “hitting it with the big hammer” and can be very useful or very painful, depending on whether your thumb is in the way of the nail.
Whether a cast is implicit or explicit is affected by the Option Strict
setting. If Option Strict
is On
(as it always should be) only widening casts can be implicit.
The explicit cast functions are:
Converts any valid string (e.g., “True”) or numeric expression to Boolean. Numeric nonzero values are converted to True
; 0
is converted to False
.
Converts numeric expression in range 0
to 255
to Byte
. Rounds any fractional part.
Returns the first character of a string as a Char.
Converts any valid representation of a date or time to Date (e.g., “January 1, 2002” is converted to the corresponding Date type).
Converts any expression that can be evaluated as a number to a Double if in the range of a Double.
Converts any expression that can be evaluated as a number to a Decimal if in the range of a Decimal.
Converts any expression that can be evaluated as a number to a Integer
if in the range of a Integer
, rounds fractional part.
Converts any expression that can be evaluated as a number to a Long
if in the range of a Long
, rounds fractional part.
Converts any expression that can be interpreted as an Object
to an Object
Converts any expression that can be evaluated as a number to a Short
if in the range of a Short
If Boolean, converts to the string “True” or “False.” If the expression can be interpreted as a date, returns a string expression of the date. For numeric expressions, the returned string represents the number.
This is a general purpose conversion function that uses the syntax
CType(expression, typename)
where expression is an expression or a variable, and typename is the data type to convert to. The first conversion in Example 16-4:
System.Console.WriteLine( _
"Freezing point of water: {0}", _
CInt
(Temperatures.FreezingPoint))
can be rewritten as:
System.Console.WriteLine( _
"Freezing point of water: {0}", _
CType
(Temperatures.FreezingPoint, Integer))
The value in the enumerated constant is cast to an integer, and that integer value is passed to WriteLine
and displayed. If you don’t specifically set it otherwise, the enumeration begins at 0
and each subsequent value counts up from the previous one.
If you create the following enumeration:
Enum SomeValues First Second Third = 20 Fourth End Enum
the value of First
will be 0
, Second
will be 1
, Third
will be 20
, and Fourth
will be 21
.
It is nearly impossible to write a Visual Basic 2005 program without creating strings . A string object holds a string of characters.
You declare a string variable using the String
keyword much as you would create an instance of any object:
Dim myString as String
A string literal is created by placing double quotes around a string of letters:
"Hello World"
It is common to initialize a string variable with a string literal:
Dim myString as String = "Hello World"
In the Visual Basic 2005 language, spaces and tabs are considered to be whitespace (so named because you see only the white of the underlying “page”). Extra whitespace is generally ignored in Visual Basic 2005 statements. Thus, you can write:
Dim myVariable as Integer = 5
or:
Dim myVariable as Integer = 5
and the compiler will treat the two statements as identical.
The exception to this rule is that whitespace within strings is not ignored. 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 indifferent.
However, there are instances when the use of whitespace is quite significant. Although the expression:
Dim myVariable as Integer = 5 'no whitespace around = sign
is the same as:
Dim myVariable as Integer=5
it is not the same as:
DimmyVariable as Integer=5 'no white space around = sign
The compiler knows that the whitespace on either side of the assignment operator is extra, but the whitespace between the keyword Dim
and the name of the variable is not extra, and is required.
This is not surprising; the whitespace allows the compiler to parse the keyword Dim
rather than some unknown term DimmyVariable
. You are free to add as much or as little whitespace between Dim
and myVariable
as you care to, but there must be at least one whitespace character (typically a space or tab).
In Visual Basic 2005, a complete program instruction is called a statement. Programs consist of sequences of Visual Basic 2005 statements . Each statement ends with a new line or a colon.
Dim myString As String = "Hello World" Dim myVariable As Integer = 5 : Dim myVar2 As Integer = 7
The colon allows you to squeeze more than one statement on a single line, but is generally considered poor programming practice because it makes for code that is harder to read and thus harder to maintain.
If your code will not fit on a single line, you may use the line continuation character, the underscore: (_) to continue a single statement on more than one line, as shown here:
System.Console.WriteLine( _
"Freezing point of water: {0}", _
CInt
(Temperatures.FreezingPoint))
All three lines are considered a single statement, because of the use of the line continuation character.
Visual Basic 2005 statements are evaluated in order. The compiler starts at the beginning of a statement list and makes its way to the bottom. This would be entirely straightforward, and terribly limiting, were it not for branching .
Methods are executed from top to bottom. The compiler reads each line of code in turn, and executes one line after another. This continues in sequence until the method branches.
There are two ways a method can branch: unconditionally or conditionally. We’ll look at each of these in turn.
The most common way to branch is by calling a method. This is an unconditional branch.
You call a method by writing its name. For example:
Method1() 'invokes Method1
It is also legal to call a VB.NET method with the optional keyword call
:
call Method1()
If you do use call
on a function, the return value is discarded. There is no advantage to this syntax, and it isn’t used in this book.
Every time the compiler encounters a method call, it stops execution in the current method and branches to the newly called method. When that method returns, execution picks up in the original method on the line just below the method call, as illustrated schematically in Figure 16-2.
In Figure 16-2, execution begins in Main
. Statements 1 and 2 execute and then the compiler sees a call to Method1
. Program execution branches to the start of Method1
, where its first three statements are executed. At the call to Method1A
execution again branches, this time to the start of Method1A
.
The four statements in Method1A
are executed and Method1A
returns. Execution resumes on the first statement after the method call in Method1
(Statement 4). Execution continues until Method1
ends, at which time execution resumes back in Main
at Statement 3. At the call to Method2
, execution again branches; all the statements in Method2
execute and then Main
resumes at Statement 4. When Main
ends, the program itself ends.
You can see the effect of method calls in Example 16-5. Execution begins in Main
, but branches to a method named SomeMethod
. The WriteLine
statements in each method assist you in seeing where you are in the code as the program executes.
Option Strict On Option Explicit On Module Module1 Sub Main() Console.WriteLine("In Main! Calling SomeMethod...") SomeMethod() Console.WriteLine("Back in Main.") End Sub 'Main Sub SomeMethod() Console.WriteLine("Greetings from SomeMethod!") End Sub 'SomeMethod End Module Output: In Main! Calling SomeMethod... Greetings from SomeMethod! Back in Main.
Program flow begins in Main
and proceeds until SomeMethod
is invoked (invoking a method is sometimes referred to as “calling
" the method). At that point, program flow branches to the method. When the method completes, program flow resumes at the next line after the call to that method.
While method calls cause unconditional branching, often you will want to branch within a method depending on a condition that you evaluate while the program is running. This is known as conditional branching.
Conditional branching statements allow you to write logic, such as “If you are over 25, then you may rent a car.”
The simplest branching statement is If
. An If
statement branches based on a condition. The condition is a Boolean
expression.An expression is a statement that evaluates to a value. A Boolean expression evaluates to True
or False
.
An If
statement says: if the condition evaluates to True
, then execute the statement, otherwise, skip it. The formal description of an if statement is:
If expression
Thenstatements
End If
An alternative one-line version is:
If expression Then statement
The use of the If
statement is illustrated in Example 16-6.
Option Strict On
Module Module1
Sub Main()
Dim valueOne As Integer = 10
Dim valueTwo As Integer = 20
Dim valueThree As Integer = 30
Console.WriteLine("Testing valueOne against valueTwo...")
If valueOne > valueTwo Then
Console.WriteLine( _
"ValueOne: {0} larger than ValueTwo: {1}", _
valueOne, valueTwo)
End If
Console.WriteLine("Testing valueThree against valueTwo...")
If valueThree > valueTwo Then
Console.WriteLine( _
"ValueThree: {0} larger than ValueTwo: {1}", _
valueThree, valueTwo)
End If
Console.WriteLine("Testing is valueTwo > 15 (one line)...")
If valueTwo > 15 Then Console.WriteLine("Yes it is")
End Sub 'Main
End Module
Output:
Testing valueOne against valueTwo...
Testing valueThree against valueTwo...
ValueThree: 30 larger than ValueTwo: 20
Testing is valueTwo > 15 (one line)...
Yes it is
In this simple program, you declare three variables, valueOne
, valueTwo
, and valueThree
. In the first If
statement, you test whether valueOne
is greater than valueTwo
.
If valueOne > valueTwo Then Console.WriteLine( _ "ValueOne: {0} larger than ValueTwo: {1}", valueOne, valueTwo) End If
Because valueOne
is less than valueTwo
, this If
statement fails (the condition returns False
), and the body of the If
statement (the statements between the If
and the End If
) never executes.
The test for greater than uses the greater-than operator (>), which is discussed in detail later in this chapter.
You then test whether valueThree
is greater than valueTwo
:
If valueThree > valueTwo Then
Console.WriteLine( _
"ValueThree: {0} larger than ValueTwo: {1}", valueThree, valueTwo)
End If
Since valueThree
(30) is greater than valueTwo
(20), the test returns True
and thus the statement executes. The statement in this case is the call to WriteLine()
, shown in bold.
Finally, Example 16-6 uses a one-line If
statement to test whether valueTwo
is greater than 15. Since this evaluates to True
, the statement that follows executes, and the words “Yes it is” are displayed.
If valueTwo > 15 Then Console.WriteLine("Yes it is")
The output reflects that the first If
statement fails, but the second and third succeed:
Testing valueOne against valueTwo... Testing valueThree against valueTwo... ValueThree: 30 larger than ValueTwo: 20 Testing is valueTwo > 15 (one line)... Yes it is
Often you will find that you want to take one set of actions when the condition tests True
, and a different set of actions when the condition tests False
. This allows you to write logic such as “If you are over 25, then you may rent a car; otherwise, you must take the train.”
The otherwise portion of the logic is executed in the else statement. For example, you can modify Example 16-6 to print an appropriate message whether or not valueOne
is greater than valueTwo
, as shown in Example 16-7.
Option Strict On
Option Explicit On
Module Module1
Sub Main()
Dim valueOne As Integer = 10
Dim valueTwo As Integer = 20
Dim valueThree As Integer = 30
Console.WriteLine("Testing valueOne against valueTwo...")
If valueOne > valueTwo Then
Console.WriteLine( _
"ValueOne: {0} larger than ValueTwo: {1}", valueOne, valueTwo)
Else
Console.WriteLine( _
"Nope, ValueOne: {0} is NOT larger than valueTwo: {1}", _
valueOne, valueTwo)
End If
End Sub 'Main
End Module
Output:
Testing valueOne against valueTwo...
Nope, ValueOne: 10 is NOT larger than valueTwo: 20
Because the test in the If
statement fails (valueOne
is not larger than valueTwo
), the body of the If
statement is skipped and the body of the Else
statement is executed. Had the test succeeded, the If
statement body would execute and the body of the Else
statement would be skipped.
It is possible, and not uncommon, to nest If
statements one within another, to handle complex conditions. It is also common to evaluate a sequence of expressions with the ElseIf
construct. The first If
/ElseIf
statement to evaluate True
will have its statements executed (and no others will even be evaluated). If none of the statements evaluates True
, the final Else
clause is executed.
Nested If
statements and long sequences of ElseIf
statements are hard to read, maintain, and debug. When you have a complex set of choices to make, the Select Case
statement is a more powerful alternative. The logic of a Select Case
statement is to “pick a matching value and act accordingly.”
Select [ Case ] testExpression [ Case expressionList [ statements ] ] [ Case Else [ else statements] ] End Select
It is easiest to understand this construct in the context of an example, as shown in Example 16-8.
Option Strict On Module Module1 Sub Main() Dim targetInteger As Integer = 15 Select Case targetInteger Case 5 Console.WriteLine("5") Case 10 Console.WriteLine("10") Case 15 Console.WriteLine("15!") Case Else Console.WriteLine("Value not found") End Select End Sub 'Main End Module Output: 15!
In Example 16-8, a value (15
) is assigned to targetInteger
. The Select Case
statement tests for the values 5
, 10
and 15
. If one matches, the associated statement is executed. The output shows that the value 15
matched, and the associated statement was executed, displaying the value. If none of the values matched, the Else
select statement would be executed.
You can check for a range of values (e.g., Case 10 To 14
).
You are not restricted to just testing for a numeric value. You can also test for String
values, and you can test ranges of string values, examining whether a target value fits alphabetically within the range (e.g., Case “Alpha To Lambda”).
A single Case
statement can test for more than one criterion: just separate them by commas:
Case "Fred", "Joe", Is < "Alpha" Console.WriteLine("Joe or Fred or < Alpha")
This case will match the strings “Fred” and “Joe” as well as any string that comes alphabetically before “Alpha.”
In a VB.NET method, you will find many situations in which you want to do the same thing again and again, perhaps slightly changing a value each time you repeat the action. This is called iteration or looping. Typically, you’ll iterate (or loop) over a set of items, taking the same action on each. This is the programming equivalent to an assembly line: take a hundred car bodies and put a windshield on each one as it comes by.
VB.NET provides an extensive suite of iteration statements
, including Do
and For
.
The semantics of a Do
loop are “Do this work while a condition is true” or “Do this work until a condition becomes true.” You can test the condition either at the top or at the bottom of the loop. If you test at the bottom of the loop, the loop will execute at least once.
The Do
loop can even be written with no conditions; in which case, it will execute indefinitely, until it encounters an Exit Do
statement.
Do
loops come in the following flavors:
Do While BooleanExpression statements Loop Do Until BooleanExpression statements Loop Do statements Loop while BooleanExpression Do statements Loop until BooleanExpression Do statements Loop
In each case, the BooleanExpression
can be any expression that evaluates to a Boolean
value of True
or False
.
The first kind of Do
loop, Do While
, executes only while the BooleanExpression
returns True
, as shown in Example 16-9.
Option Strict On Module Module1 Sub Main() Dim counterVariable As Integer = 0 Do While counterVariable < 10 Console.WriteLine("counterVariable: {0}", counterVariable) counterVariable = counterVariable + 1 Loop ' While counterVariable < 10 End Sub 'Main End Module Output: counterVariable: 0 counterVariable: 1 counterVariable: 2 counterVariable: 3 counterVariable: 4 counterVariable: 5 counterVariable: 6 counterVariable: 7 counterVariable: 8 counterVariable: 9
The second version of Do
:
Do Until BooleanExpression statements Loop
executes until the BooleanExpression
returns True
.
Be very careful when looping to a specific value. If the value is never reached or is skipped over, your loop can continue without end, causing your program to “hang.”
The two constructs are closely related; which one you use will depend on the semantics of the problem you are trying to solve. That is, use the construct that represents how you think about the problem. If you are solving this problem: “keep winding the box until the Jack pops up,” then use a Do Until
loop. If you are solving this problem: “As long as the music plays, keep dancing,” then use a Do While
loop, though either construct will work (“keep dancing until the music stops.”)
The two variants:
Do statements Loop while BooleanExpression Do statements Loop until BooleanExpression
are used when you want to ensure that the loop runs at least once, whatever the starting conditions. Thus, although your counterVariable
might be initialized to 100, you want to make sure the loop runs once anyway. You’ll use the Do...
Loop
While
construct.
You can break out of any Do
loop with the Exit Do
statement. You must break out of the final Do
construct:
Do statements Loop
because otherwise it will never terminate. You typically use this construct when you do not know in advance what condition will cause the loop to terminate (e.g., the termination may be in response to user action).
As further proof that there are many ways to accomplish the same thing, VB.NET also offers a While
loop construct that is closely related to the Do...While
loops. The syntax is:
while BooleanExpression statements End While
When you need to iterate over a loop a specified number of times, you can use a For
loop with a counter variable. The syntax of the For
loop is:
Forvariable
=expression
toexpression
[step expression
] statements Next [variable-list
]
The simplest and most common form of this statement creates a loop variable to count through the iterations of the loop. For example, you might create an integer variable loopCounter
that you will use to step through a loop ten times, as shown in Example 16-10.
Option Strict On Module Module1 Sub Main() Dim loopCounter As Integer For loopCounter = 0 To 9 Console.WriteLine("loopCounter: {0}", loopCounter) Next End Sub 'Main End Module Output: loopCounter: 0 loopCounter: 1 loopCounter: 2 loopCounter: 3 loopCounter: 4 loopCounter: 5 loopCounter: 6 loopCounter: 7 loopCounter: 8 loopCounter: 9
The variable (loopCounter
) can be of any numeric type. For example, you might initialize a Single
rather than an Integer
, and step up through the loop from 0.5
to 9
.
You can also modify multiple variables on each Next
statement. This allows you to nest one For
loop within another. You might use an outer and an inner loop to iterate through the contents of collections. A simple example of this technique is shown in Example 16-11.
Option Strict On Module Module1 Sub Main() Dim outer As Integer Dim inner As Integer For outer = 3 To 6 For inner = 10 To 12 Console.WriteLine("{0} * {1} = {2}", _ outer, inner, outer * inner) Next inner, outer End Sub 'Main End Module 3 * 10 = 30 3 * 11 = 33 3 * 12 = 36 4 * 10 = 40 4 * 11 = 44 4 * 12 = 48 5 * 10 = 50 5 * 11 = 55 5 * 12 = 60 6 * 10 = 60 6 * 11 = 66 6 * 12 = 72
As an alternative to updating both counters in the same Next
statement, you can provide each nested For
loop with its own Next
statement:
For outer = 3 To 6 For inner = 10 To 12 Console.WriteLine("{0} * {1} = {2}", _ outer, inner, outer * inner) Next inner Next outer
When you update a single value in a Next
statement, you are free to leave off the variable you are updating. Thus, the previous code is identical to this code:
For outer = 3 To 6 For inner = 10 To 12 Console.WriteLine("{0} * {1} = {2}", _ outer, inner, outer * inner) Next Next
An operator is a symbol (e.g., =, >, +) that causes VB.NET to take an action. That action might be assignment (=), addition of two values (+), or comparison of two values (>).
The simplest is the assignment operator:
myVariable = 15;
The single equal sign (=) is used to assign a value (15
) to a variable (myVariable
). If
statements often use comparison operators
:
if ( valueOne > valueTwo )
This If
statement compares valueOne
with valueTwo
, and if the former is larger than the latter, the test evaluates True
, and the If
statement executes.
VB.NET uses seven arithmetic operators , six for standard calculations (+, −, *, ^, /, and ) and a seventh to return the remainder when dividing integers.
VB.NET offers two division operators: / and . The right-facing division operator (/) returns a floating-point answer. If you divide 12/5, the answer is 2.4, as you would expect. This answer is returned as a Double
. If you assign the returned value to an Integer
, the decimal part is lopped off, and the result will be 2. If Option Strict
is On
(as it should be), you cannot assign the result to an Integer
without explicitly casting, because you would lose the decimal portion of the answer.
The left-facing division operator () returns an Integer
value. If you divide 125, the result is returned with a truncated integer: 2. No cast is needed (even with Option Strict On
) because you’ve explicitly asked for the integer value.
To find the remainder in integer division, use the modulus operator (Mod
). For example, the statement 17 Mod 4
returns 1
(the remainder after integer division).
The modulus operator is more useful than you might imagine. When you perform modulus n on a number that is a multiple of n, the result is zero. Thus, 80 Mod 10 = 0
because 80 is an even multiple of 10. This allows you to set up loops in which you take an action every nth time through the loop, by testing a counter to see if Mod n
is equal to zero.
Relational operators are used to compare two values, and then return a Boolean
(True
or False
). The greater-than operator (>), for example, returns True
if the value on the left of the operator is greater than the value on the right. Thus, 5 > 2 returns the value True
, while 2 > 5 returns the value False
.
The relational
operators for VB.NET are shown in Table 16-5. This table assumes two variables: bigValue
and smallValue
, in which bigValue
has been assigned the value 100
and smallValue
the value 50
.
Name |
Operator |
Given this statement |
The expression evaluates to |
Equals |
= |
|
|
Not Equals |
|
|
|
Greater than |
> |
|
|
Greater than or equals |
|
|
|
Less than |
|
|
|
Less than or equals |
|
|
|
Notice that some operators are composed of two characters. For example, greater than or equal to is created with the greater-than symbol (>) and the equal sign (=). You may place these symbols in either order (>=
or =>
)
The VB.NET equality operator (=) and assignment operator (=) use the same symbol.
When you write:
If myX = 5 Then myX = 7
the first use of the = symbol is the equality operator (if myX
is equal to 5
), the second use is the assignment operator (set myX
to the value 7
). The compiler figures out which is meant by context. (Eat your heart out, C# programmers!)
If
statements test whether a condition is True
. Often you will want to test if two conditions are both True
, only one is True
, or none is True
. VB.NET provides a set of logical
operators
for this, as shown in Table 16-6. This table assumes two variables, x
and y
, in which x
has the value 5
and y
the value 7
.
Operator |
Given this statement |
The expression evaluates to |
Logic |
|
|
|
Both must be |
|
|
|
Short circuits the test, y is never tested. If the left side fails, the right is not tested. |
|
|
|
Either or both must be |
|
|
|
Short circuited, since |
|
|
|
True only if one (and only one) statement is |
|
|
|
Expression must be |
The And
operator tests whether two statements are both True
. The first line in Table 16-6 includes an example that illustrates the use of the And
operator:
x = 3 And y = 7
The entire expression evaluates False
because one side (x = 3
) is False
.
With the Or
operator, either or both sides must be True
; the expression is False
only if both sides are False
. So, in the example in Table 16-6:
x = 3 Or y = 7
the entire expression evaluates to True
because one side (y = 7
) is True
.
The Xor
logical operator is used to test if one (and only one) of the two statements is correct. Thus:
x = 5 Xor y = 7
evaluates to False
, because both statements are True
. The Xor
statement is False
if both statements are True
, or if both statements are False
; it is True
only if one and only one statement is True
.
With a Not
operator, the statement is True
if the expression is False
, and vice versa. So, in the accompanying example:
Not x = 3
the entire expression is True
because the tested expression (x = 3
) is False
. (The logic is: “it is True
that it is not True
that x
is equal to 3
.”)
The compiler must know the order in which to evaluate a series of operators. For example, if I write:
myVariable = 5 + 7 * 3
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
). Since we’re evaluating left to right, the assignment has been done, so the value 36
is thrown away. This is clearly not what is intended.
The rules of precedence
tell the compiler which operators to evaluate first. As is the case in algebra, multiplication has higher precedence than addition, so 5 + 7 * 3
is equal to 26
rather than 36
. Both addition and multiplication have higher precedence than assignment, so the compiler will do the math, and then assign the result (26
) to myVariable
only after the math is completed.
In VB.NET, parentheses are used to change the order of precedence much as they are in algebra. Thus, you can change the result by writing:
myVariable = (5+7) * 3
Grouping the elements of the assignment in this way causes the compiler to add 5 + 7
, multiply the result by 3
, and then assign that value (36
) to myVariable
.
Within a single line of code, operators are evaluated in the following order:
Parentheses
Arithmetic
Concatenation
Comparison
Logical
Assignment
Comparison operators are evaluated left to right. Arithmetic operators are evaluated in this order:
Exponentiation (^)
Division and multiplication (/, *)
Integer division ()
Modulo operator (Mod
)
Addition and subtraction (+,−)
The logical operators are evaluated in this order:
Not
And
Or
Xor