✓ | The basic structure of Microsoft Visual Basic .NET. |
✓ | How Visual Basic .NET differs from earlier forms of Visual Basic. |
Just as ASP.NET is a much different beast than classic ASP, Visual Basic .NET differs considerably from its predecessors. For one thing, there’s no longer any difference in the Visual Basic that you use in ASP.NET pages and the Visual Basic that comes with the full Microsoft Visual Studio package. Visual Studio does provide an excellent graphical development environment, but you can use a text editor and get all the same Visual Basic language features. In other words, there’s no such thing as VBScript .NET, as opposed to Visual Basic 7 .NET. There’s just one Visual Basic .NET for everyone.
Lest euphoria overcome you, this one unified Visual Basic .NET is a considerable departure from all the versions of Visual Basic that came before it. Normal, incremental improvement accounts for some of this, but the main reason is compatibility with the common language runtime (known as the runtime). As you should recall from Chapter 2, the runtime provides a common run-time environment for all programs compiled by any .NET compiler. By implementing the runtime, Microsoft intends to end, once and for all, the situation in which some programming languages are much better than others for writing certain kinds of programs. This is a noble and worthwhile goal, but it does require a certain amount of uniformity among the various languages. Hence, Visual Basic has seen a staggering number of changes. For users of C++, there’s now a whole new language, called C#.
A complete guide to Visual Basic .NET is clearly beyond the scope of this book; in fact, it could fill several books. Nevertheless, this chapter provides a brief introduction to Visual Basic .NET, concentrating on fundamentals and on features that have changed. This information should be enough to get you started.
Remember Fuzzy Wuzzy, the bear who wasn’t fuzzy? Well, within ASP.NET, Visual Basic isn’t visual. It can’t display windows or dialog boxes, and when running within an ASP.NET page, it doesn’t even support MsgBox or InputBox functions. The reason for this is quite simple.
Because an ASP.NET page runs on the Web server, any dialog boxes it displayed would appear on the server’s console, inaccessible to the Web visitor. Of course, an ASP.NET page can write the HTML to create visual displays of any type on the Web visitor’s browser.
In general, Visual Basic statements begin anywhere on a line and end where the line ends. There are no semicolons, periods, or other punctuation at the end of a Visual Basic statement. Except within literals, any number of contiguous space or tab characters are equivalent to one space. Blank lines are irrelevant except for readability.
To continue a statement onto a second line, code a space and an underscore at the end of the continued line. The following code shows one statement continued across two lines:
lngZeta = lngAlpha + lngBeta + lngGamma _ + lngDelta + lngEpsilon
With two exceptions, Visual Basic treats anything between an apostrophe and the end of a line as comments. The exceptions are as follows:
An apostrophe enclosed in quotation marks, as in this example, doesn’t mark the beginning of a comment:
strReply = "No, I don't think so."
You can’t code comments after a continuation character. The following, for example, would be an error:
lngZeta = lngAlpha + lngBeta + lngGamma _ ' Coffee break + lngDelta + lngEpsilon
If you’re accustomed to using VBScript (the version of Visual Basic that classic ASP developers used), you’re accustomed to using only two data types: Variants and Objects. Well, in Visual Basic .NET, Microsoft has eliminated the Variant type, substituted Object as the default type, and then discouraged you from using the Object type. Instead, Microsoft encourages you to use the specific data types listed in the "Data Type Summary" table.
Data Type Summary | |||||
---|---|---|---|---|---|
Category | Type | Bits | Bytes | LiteralTypeCharacter | TypicalValues |
Character | Char | 16 | 2 | C | "A"C |
String | "Bits" | ||||
Date | Date | 64 | 8 | #...# | #2/13/2002# |
Decimal | Decimal | 128 | 16 | D | 5.00D |
Floating Point | Single | 32 | 4 | F | 5.123S |
Double | 64 | 8 | R | 5.123R | |
Integer | Byte | 1 | 1 | 0–255 | |
Short | 16 | 2 | S | 5S | |
Integer | 32 | 4 | I | 5I | |
Long | 64 | 9 | L | 5L | |
Logical | Boolean | 16 | 2 | True | |
False | |||||
Object | Object | 32 | 4 |
To declare a variable, use the Dim statement as shown:
Dim strDescription As String Dim intQuantity As Integer = 0 Dim booAnswer As Boolean = False
Specifying a value is optional. If you don’t assign a value when you declare a variable, Visual Basic assigns an empty string, zero, or false, depending on the data type.
Many Web developers find it valuable to begin the names of their variables with an abbreviation, one or three letters long, of the variable’s data type. This trick saves a lot of time otherwise spent debugging type conversion problems.
If you declare a variable without specifying a data type, Visual Basic makes the variable an Object. Later, when your code is running, an Object variable can refer to any of the other data types, but assigning or changing object types at run time (a practice called late binding or run-time binding) is a time-consuming operation. For this reason, it’s best to use specific data types when declaring variables.
The opposite of late (or run-time) binding is early (or compile-time) binding. Early binding is preferable because the compiler can assemble much better code when it knows the exact type of each variable beforehand.
In all previous versions of Visual Basic, you didn’t need to code Dim statements for each variable unless you began the program or Web page with the statement:
Option Explicit
This is another area where Visual Basic .NET has changed: Option Explicit is now in effect unless you specifically turn it off. Don’t do this! The time and trouble of coding a Dim statement for each variable is nothing compared to the grief of debugging program code when a misspelled variable name provides an empty value where you expected real data. In addition, all Visual Basic variables not defined with a Dim statement are defined as Objects, and therefore incur the performance penalty of late binding. For more information about turning the Explicit option on or off, refer to "Coding the @ Page Directive" in Responding to Web Form Events in Chapter 3.
The following data types warrant particular mention:
String. This data type can accommodate strings as long as 2 billion double-byte characters. (The precise maximum length is 231-1.)
Date. All languages based on the .NET framework store dates as 64-bit integers. These represent dates ranging from January 1 of the year A.D. 1 to December 31, 9999, and times from 0:00:00 to 23:59:59.
This additional capacity is a significant change from previous versions of Visual Basic, which stored dates as double-precision, floating-point values denoting days since December 30, 1899. Values to the left of the decimal represented the date, and values to the right of the decimal represented the time. Under this scheme, adding a week to a date was as simple as adding 7. Time flies, however, and with the new Visual Basic .NET date format, this technique no longer works. To manipulate dates, you must use the methods built into the .NET Date class. For more information about manipulating dates, refer to "Manipulating Dates" later in this chapter.
Decimal. This data type replaces the Currency type that was part of Visual Basic 6.
Short. This data type didn’t exist in Visual Basic 6. In Visual Basic .NET, it provides a way to declare 16-bit integers.
Integer. This data type is 32 bits in Visual Basic .NET. In Visual Basic 6, it was 16 bits.
Long. This data type is 64 bits in Visual Basic .NET. In Visual Basic 6, it was 32 bits.
Boolean. When you assign other numeric types to a Boolean value, 0 becomes False and all other values become True. When you assign Boolean values to other data types, False becomes 0 and True becomes 1.
Object. Don’t make the mistake of thinking that you must declare all your objects with a data type of Object. This approach works, but it forces the compiler to use late binding when your code runs and starts using the object. It’s much better to declare object variables with a specific object type. For example:
Dim clrBlack as Color
Most objects have a so-called constructor method that runs each time a program creates an object of the given type. If you defined three Color objects, for example, the constructor would run three times (once to initialize each object).
If that’s not cool enough, most constructor methods can accept parameters from you, the developer—effectively initializing the object with any values you want. All you do is add the keyword New and parameters to your Dim statement:
Dim dteGroundHog As New Date(2002, 2, 2)
If you declare several variables with a single Dim statement, all the variables will be the same type. In the following statement, for example, the lngJohn, lngTime, and lngGone variables will all be Long:
Dim lngJohn, lngTime, lngGone As Long
Previous versions of Visual Basic would designate lngJohn and lngTime as Variants and lngGone as Long.
Like Visual Basic 6 (and unlike VBScript), Visual Basic .NET supports user-defined types. These are basically structures that contain several variables of other types. You can access the whole structure as a single unit, or you can access its members individually.
A structure declaration consists of a Structure statement, then one or more member definitions, and then an End Structure statement. (Visual Basic 6 used a Type statement rather than a Structure statement.) Here’s an example:
Structure stcAddress Dim strStreet As String Dim strCity As String Dim strState As String Dim strPostCode As String Dim strCountry As String End Structure
Once you’ve defined this structure, you can use it to define other variables. Suppose, for example, that you coded
Dim adrMyAddress As stcAddress Dim adrYourAddress As stcAddress
You could then code statements such as
adrMyAddress.strStreet = "1600 Pennsylvania Avenue" adrMyAddress.strCity = "Washington" adrMyAddress.strState = "DC" adrMyAddress.strPostCode = "20500" adrMyAddress.strCountry = "USA" adrYourAddress = adrMyAddress
Here’s the complete syntax for declaring a structure:
[Public|Private|Protected] Structure structname {Dim|Public|Private|Friend} member1 As datatype1 ... {Dim|Public|Private|Friend} memberN As datatypeN End Structure
The keywords Public, Private, Protected, and Friend control the degree of access to structures you define within a class. The table in Chapter 8 later in this chapter explains these keywords. Variables you declare without these keywords—using only the Dim keyword—are available everywhere within the region that contains the Dim statement. If a Dim statement is within a subroutine, the variable is available only within that subroutine. If a Dim statement is within a module, class, or structure, the variable is available anywhere within that module, class, or structure. For more information about defining classes, refer to "Defining Subroutines, Functions, and Classes" later in this chapter.
The following table lists the built-in functions Visual Basic .NET provides for converting one data type to another. These functions accept arguments of almost any data type and convert them to the types listed. If the conversion isn’t possible, the function will raise an exception.
Visual Basic .NET Type Conversion Functions | ||
---|---|---|
Result Data Type | Function | Description |
Integer | Asc | Converts the first letter in a string to a number between 32768 and -32767 or, if the operating system doesn’t support double-byte characters, between 0 and 255. |
Integer | AscW | Converts the first letter in a string to a number between 32768 and -32767. |
Boolean | CBool | Returns False if the argument is zero and True otherwise. |
Char | CChar | Returns the character corresponding to argument values 0–65535. |
String | Chr | Returns the character corresponding to argument values 0–255 or, if the operating system supports double-byte characters, between -32768 and 65535. |
String | CStr | Each of these functions converts an |
Byte | CByte | expression to the data type in the first |
Short | CShort | column. If the value of the expression |
Integer | CInt | makes this impossible, an exception |
Long | CLng | occurs. Attempting to evaluate the |
DateTime | CDate | following expression, for example, |
Single | CSng | will raise an exception: |
Double | CDbl |
|
Decimal | CDec | |
Object | CObj |
Like most programming languages, Visual Basic .NET supports the use of literals. A literal is a value, such as 503, 2.5, or "doughnut", that you code in place of a variable. Literal values are read-only. You can’t change the value of 2 by coding a statement such as the following:
2 = 1 + 1 + 1
Constants are read-only named values. The following statement, for example, defines a constant named PSWD that’s equal to "sesame":
CONST PSWD = "sesame"
Having coded this statement, you could use the name PSWD instead of the value "sesame" in your code, making it easier to find and update the password when necessary. Constants are also a good solution when you use the same value several times in your code and it’s important that you code this value exactly the same way in each instance.
You can also use simple expressions to define the value of constants. The declarations below illustrate this:
CONST ENOUGH = 100 CONST TOO_MUCH = ENOUGH + 1
However, you can use only expressions that the compiler can evaluate at compile time. The following declaration would produce a compiler error because the compiler can’t predict what the value of Now() will be when the Web page actually runs:
CONST THE_DATE = Now()
Constants can also be part of the object model for controls or components you’re working with. Importing a namespace, for example, typically makes a large number of constants available to your ASP.NET page. Your code will be easier to read, easier to debug, and more accurate if you use the constants supplied for use with a certain method or property, rather than hard-coding values that have no obvious meaning. The documentation for the namespace, property, or method will list these constants.
Constants and literals in Visual Basic .NET have data types, just as variables do. The table below lists the default data types for various kinds of literals. The default data type for a constant is the data type of its literal.
Default Data Types For Literals | ||
---|---|---|
Type of value | Example | Data Type |
Integral numbers | 321 | Integer |
Floating-point numbers | 3.12 | Double |
True or False | True | Boolean |
Character values | "trouble" | String |
To include quotation marks in a string literal, code two quotation marks where you want one to appear. The following code, for example, is valid:
strText = "Tom said, ""Sorry,"" but Anne wasn't impressed."
If you wish, you can also code the data type of a constant explicitly. The possibilities are Boolean, Char, String, Byte, Integer, Short, Long, DateTime, Single, Double, and Decimal. Here’s an example:
Public Const NORM_TEMP As Single = 37
There are at least three reasons for coding constant and literal types explicitly:
Explicitly declaring data types is unambiguous.
Typed code is easy to read and maintain.
When the Strict option is in effect, failing to declare a data type for a constant will produce a compiler error.
There are two ways to force the data type of a literal. For some data types, you enclose the literal value with special enclosing characters. For others, you append a special type character to the value. The enclosing characters and type characters for each data type are shown below. The literal 5S, for example, indicates a Short with a value of 5.
Visual Basic .NET Enclosing Characters and Type Characters | ||
---|---|---|
Data Type | Enclosing character | Appended type character |
Boolean | (none) | (none) |
Char | " | C |
Byte | (none) | (none) |
Short | (none) | S |
Integer | (none) | I or % |
Long | (none) | L or & |
DateTime | # | (none) |
Single | (none) | F or ! |
Double | (none) | R or # |
Decimal | (none) | D or @ |
Visual Basic .NET provides the built-in constants listed in the table "Visual Basic .NET Print and Display Contents." These are frequently useful when you need to include nonprintable characters in an output stream. The notation Chr(13) means ASCII character 13, the carriage return.
Visual Basic .NET Print and Display Constants | ||
---|---|---|
Constant | Equivalent | Description |
vbCrLf | Chr(13) & Chr(10) | Carriage return/linefeed character combination. |
vbCr | Chr(13) | Carriage return character. |
vbLf | Chr(10) | Linefeed character. |
vbNewLine | Chr(13) & Chr(10) | New line character. |
vbNullChar | Chr(0) | Character having value 0. |
vbNullString | String having value 0 | Not the same as a zero-length string (""); used for calling external procedures. |
vbObjectError | -2147221504 | Error number. User-defined error numbers should be greater than this value. |
vbTab | Chr(9) | Tab character. |
vbBack | Chr(8) | Backspace character. |
vbFormFeed | Chr(12) | Not useful in Microsoft Windows. |
vbVerticalTab | Chr(11) | Not useful in Microsoft Windows. |
An operator is a symbol or keyword that tells Visual Basic to take action on one or more expressions. In the expression 1 + 2, for example, the + operator tells Visual Basic to add the two numbers. The next few sections describe the basic operators that Visual Basic.NET provides.
Visual Basic .NET, like all previous forms of Visual Basic, supports the arithmetic operators listed in the following table.
Language Element | Description |
---|---|
^ | Exponentiation |
– | Subtraction |
* | Multiplication |
/ | Floating-point division |
Integer division | |
Mod | Integer remainder |
+ | Addition |
The exponentiation and floating-point division operators always return a Double result. The others return the operand data type with the greatest range. To understand what this means, first consider the following order of ranges:
Byte, Short, Integer, Long, Single, Double, Decimal
If the operands of, say, an addition are a Byte and a Short, the result will be a Short. If the operands are a Long and a Decimal, the result will be a Decimal. The data type that can hold the largest number will be the data type of the result.
The assignment operator is, as always, the equal sign. To add the value of a variable named decUnitPrice to the value of a variable named decTotalPrice, you would code
decTotalPrice = decTotalPrice + decUnitPrice
In Visual Basic .NET, you can achieve the same result by coding
decTotalPrice += decUnitPrice
This second form adds the value of the expression on the right of the assignment operator to the variable you specify on the left. This form saves you the trouble of typing the receiving variable name twice. The same trick works for all these operators:
^= | Exponentiation |
*= | Multiplication |
/= | Floating-point division |
= | Integer division |
+= | Addition |
-= | Subtraction |
&= | Concatenation |
Visual Basic .NET no longer supports the Set and Let statements. The Let statement has been extraneous for some time. Instead of coding
Let strThere = strLight
you can simply code
strThere = strLight
If you want two variables to point to the same object, code
objEct1 = objEct2
If you want objEct1 to point to a brand new object, code
objEct1 = New <object type> (<constructor params, if any>)
When you concatenate (that is, join) strings, you must always include spaces around the & operator. If you try to code an expression such as a&b& c, the compiler will report a syntax error and halt. You must code a & b & c.
Visual Basic .NET supports the comparison operators listed in the following table. If both operands are numeric, Visual Basic .NET compares them numerically. If one or both are characters or strings, Visual Basic .NET compares them as case-sensitive text.
Visual Basic .NET Comparison Operators | |
---|---|
Comparison Operator | Description |
= | Equal |
<> | Not equal |
< | Less than |
> | Greater than |
<= | Less than or equal |
>= | Greater than or equal |
Like | Matches pattern |
Is | Returns True if both operands point to the same object. |
The Like operator compares a string to a pattern. If the two match, the comparison is True; otherwise, of course, it’s False. If both the string and the pattern are empty, the result is True. If only one is empty, the result is False. The available patterns are listed in the following table.
Characters in Pattern | Matches in String |
---|---|
? | Any single character |
* | Zero or more characters |
# | Any single digit (0–9) |
[charlist] | Any single character in charlist |
[!charlist] | Any single character not in charlist |
Using the Like operator requires knowing its quirks and peculiarities. Here are some tips:
Visual Basic .NET compares a bracket expression in the pattern—no matter how long—to exactly one character position in the comparison string. The expression
"abc" Like "a[xyzb]c"
is true because a matches a, b matches one of the characters in xyzb, and c matches c.
To match the left bracket ([), question mark (?), number sign (#), and asterisk (*), enclose them in brackets. In the following example, the first expression is True because the asterisk matches any character. The second is False because "X" doesn’t equal the specific character *.
"aaXaa" Like "aa*aa" "aaXaa" Like "aa[*]aa"
You can’t use the right bracket (])to match itself inside a group, but you can use it outside of a group as an individual character. The pattern ac[em]or]uv doesn’t match ac]uv, for example, because [em]or] isn’t a group that matches e, m, ], o, or r.
The pattern ac[em]or]uv does match aceor]uv because [em] matches e.
To include a range of characters within the brackets, code the character with the lower sort order, a hyphen (-), and then the character with the higher sort order. The following expressions are equivalent:
"A" Like "[0-9A-F]" "A" Like "[0123456789ABCDEF]"
If you code a hyphen as the first or last character within brackets, it matches only another hyphen character. The expression below is true because the hyphen is one of the characters in the first group and A is one of the characters in the second group.
"-A" Like "[-02468][A-Z]"
An exclamation point (!) at the beginning of a bracketed group matches any character except those in the group. The first of the following expressions is True while the second is False:
"void" Like "[!a-u]oid" "-oid" Like "[!-ad]oid"
Outside of any brackets, an exclamation point matches itself.
An empty group ([]) signifies an empty string ("").
You can concatenate strings using either the plus (+) operator or the ampersand (&) operator. The following statements are equivalent:
strResult = "Welcome to " + "my circus." strResult = "Welcome to " & "my circus."
Experienced Web developers, however, never use the plus (+) operator for joining strings. There are two very good reasons for this:
It’s very easy to code an expression such as a + b that you think will concatenate the variables a and b. However, if the variables are numeric, this expression actually adds them. The expression a & b always performs a concatenation.
Visual Basic .NET will halt with a compilation error if you use the plus (+) operator to concatenate a mixture of string variables and numeric variables. The ampersand (&) operator, however, does the same job without complaining at all.
In the end it comes down to this: use the concatenation operator (&) for concatenating and the addition operator (+) for adding. What could be easier than that?
Visual Basic .NET uses the same logical operators as prior versions of Visual Basic, as well as two new ones, as listed in the following table.
Operator | Operands | Result |
---|---|---|
Not | 1 | True if operand is False |
False if operand is True | ||
And | 2 | True if both operands are True |
False if either operand is False | ||
Or | 2 | True if either operand is True |
False if both operands are False | ||
Xor | 2 | True if one operand is True |
False if both operands are True or False | ||
AndAlso | 2 | Same as And but short-circuited |
OrElse | 2 | Same as Or but short-circuited |
Most use of these operators involves Boolean operands, as shown in the following expression:
(lngOrderQty > 0) And (lngOnHandQty > 0)
The Not operand, when applied to a integer value, changes all the zero bits to one and all the one bits to zero. An integer value, in this case, means a value of type Byte, Short, Integer, or Long.
When used on integral operands, And, Or and Xor perform bitwise arithmetic. This applies the operator to the first bit of each operand, then to the second bit of each operand, and so forth.
To understand the difference between And and AndAlso, consider the following expression:
IsNumeric(strQuantity) And (clng(strQuantity) > 0)
Visual Basic uses the following procedure to evaluate this expression:
Determine whether Visual Basic .NET can convert the value in strQuantity to a number. If this conversion is possible, return True. Otherwise, return False.
Convert the value in strQuantity to a Long integer and compare the result to zero. If the result is greater than zero, return True. If it’s less than or equal to zero, return False.
Examine the results from steps 1 and 2. If both are True, return True. Otherwise, return False.
This situation presents a problem because if strQuantity contains a nonnumeric value such as xyz, executing the expression clng(strQuantity) will throw an exception. Web developers in the past solved this by nesting If statements as shown here:
If IsNumeric(strQuantity) Then
If (clng(strQuantity) > 0) Then
' Code that does the work goes here.
End If
End If
But the new AndAlso operator provides a more elegant solution:
IsNumeric(strQuantity) AndAlso (clng(strQuantity) > 0)
This code tells Visual Basic .NET that if IsNumeric(strQuantity) turns out to be False, it shouldn’t bother evaluating (clng(strQuantity) > 0). After all, if the first operand of an And expression is False, the entire And expression will be False no matter the state of the second operand.
Similarly, the OrElse operator skips evaluating the second operand if the first operand is True. If the first operand of an Or expression is True, the entire Or expression will be True no matter the state of the second operand.
The AddressOf operator returns the address of a subroutine or function. This is a useful tool for situations in which you must supply the address of a procedure that ASP.NET will call when a specific event occurs.
The GetType operator returns the type object of the specified type. The expression GetType(Integer), for example, returns the base object that defines the entire Integer class. This expression can be useful for getting various information about the type, such as its properties, methods, and events.
Visual Basic .NET stores times and dates in the same way as all other .NET languages and components. Specifically, they’re 64-bit integers that count the number of 100-nanosecond "ticks" since midnight, Coordinated Universal Time, January 1 of the year 1 in the Gregorian calendar. The time value for one second after midnight on 1-Jan-0001 is 10,000,000.
Coordinated Universal Time (UTC) is what you probably know as Greenwich Mean Time (GMT). Coordinated Universal Time, however, is the newer term that Microsoft uses in all its documentation.
Previous versions of Visual Basic stored dates as floating-point numbers. The integer part counted the number of days since December 30, 1899, and the fractional part represented a time of day. The number 2.25, for example, meant January 1, 1900, at 6:00 A.M. This system made it easy to determine the difference in days between two dates, to add 7 days to a certain date, and so forth. Unfortunately, these sorts of computations no longer produce meaningful results. Adding 7 to a date in the new DateTime format adds 700 nanoseconds.
DateTime comparisons such as greater than and less than still work reliably. Equality comparisons work too, provided that the margin of error is less than 100 nanoseconds.
You can specify DateTime values in code either by enclosing a suitably formatted string in number signs or by using the DateTime constructor method. The following pairs of statements are equivalent:
Dim dtmDateDue as DateTime = #12/31/2002# Dim dtmDateDue as New DateTime(2002, 12, 31) dtmDateDue = #12/31/2002# dtmDateDue = New DateTime(2002, 12, 31) dtmDateDue = #12/31/2002 1:30 PM# dtmDateDue = New DateTime(2002, 12, 31, 13, 30, 0)
When you use the DateTime constructor method, you can specify one, three, six, or seven arguments. These have the following significance:
1 Ticks
3 Year, Month, Day
6 Year, Month, Day, Hour, Minute, Second
7 Year, Month, Day, Hour, Minute, Second, Millisecond
In addition to changing the date format, Visual Basic .NET drops support for several date functions that earlier versions of Visual Basic have supported for some time. These legacy functions, along with the comparable Visual Basic .NET functions, are listed in the table below.
Date Functions Dropped in Visual Basic .NET | |||
---|---|---|---|
Legacy Function | Visual Basic .NET Replacement | Type | Comments |
Date | Today | DateTime | Gets or sets the system date. |
Date$ | DateString | String | Gets or sets the system date. |
Time | TimeOfDay | DateTime | Gets or sets the system time. |
Time$ | TimeString | String | Gets or sets the system time. |
Now | Now (note) | DateTime | Gets the system date and time. |
Timer | Timer(note) | Single | Gets the number of seconds elapsed since midnight. |
Visual Basic .NET continues to support all the remaining date and time functions shown in the following table, taking the new DateTime format into account as necessary.
Result Type | Name | Description | Argument Type |
---|---|---|---|
Boolean | IsDate | Indicates whether Visual Basic .NET can convert an expression to a date. | String |
DateTime | DateAdd | Adds a specified interval. | DateTime |
DateTime | DateSerial | Returns the DateTime value for a given year, month, and day. | Integers |
DateTime | TimeSerial | Returns the DateTime value for a given hour, minute, and second. | Integers |
DateTime | TimeValue | Returns the DateTime value for a given time. | String |
DateTime | DateValue | Returns the DateTime value for a given date. | String |
Integer | DatePart | Returns the specified part of a given date. | DateTime |
Integer | Year | Returns the year. | DateTime |
Integer | Month | Returns the month of the year. | DateTime |
Integer | Day | Returns the day of the month. | DateTime |
Integer | Hour | Returns the hour of the day. | DateTime |
Integer | Minute | Returns the minute of the hour. | DateTime |
Integer | Second | Returns the second of the minute. | DateTime |
Integer | Weekday | Returns the day of the week. | DateTime |
Long | DateDiff | Returns the number of intervals between two dates. You can specify intervals of minutes, days, years, and so forth. | Strings, DateTime |
String | MonthName | Returns the name of a given month. | Integer |
String | WeekdayName | Returns the name of a given day of the week. | Integer |
If none of these functions serve your needs, then perhaps one of the many date and time functions built into the .NET Framework will help. For starters, the following expressions return the minimum and maximum permissible date values:
DateTime.MaxValue DateTime.MinValue
Using the methods listed in the table "DateTime Public Static (Shared) Methods" requires a similar notation. The following expression, for example, returns False because the year 2100 won’t be a leap year:
DateTime.IsLeapYear(2100)
DateTime Public Static (Shared) Methods | |||
---|---|---|---|
Result type | Name | Description | Argument Type |
Compare | Integer | Compares two DateTime objects and returns -1, 0, or +1, depending on their relative values. | DateTimes |
DaysInMonth | Integer | Returns the number of days in the specified year and month. | Integers |
Equals | Integer | Indicates whether two variables point to the same DateTime object. | DateTimes |
FromFileTime | DateTime | Returns the DateTime value that corresponds to an operating system file time stamp. | Long |
FromOADate | DateTime | Returns a DateTime equivalent to the specified OLE Automation Date. | Double |
IsLeapYear | Boolean | Indicates whether a given year is a leap year. | Integer |
Parse | DateTime | Converts a String to its DateTime equivalent. | String |
ParseExact | DateTime | Converts a String to its DateTime equivalent. The format of the String representation must exactly match a specified format. | String |
If you still haven’t found a function that meets your needs, consider the DateTime properties listed in the "DateTime Public Instance Properties" table. These properties are available for every DateTime object. If the variable dtmDateDue is a DateTime value, the following expressions return its year, month, day, hour, and minute values:
dtmDateDue.Year dtmDateDue.Month dtmDateDue.Day dtmDateDue.Hour dtmDateDue.Minute
DateTime Public Instance Properties | ||
---|---|---|
Result Type | Property | Description |
DateTime | Date | Gets the date component. |
DateTime | TimeOfDay | Gets the time-of-day component. |
Integer | Year | Gets the year component. |
Integer | Month | Gets the month component. |
Integer | Day | Gets the day of the month. |
Integer | Hour | Gets the hour component. |
Integer | Minute | Gets the minute component. |
Integer | Second | Gets the seconds component. |
Integer | Millisecond | Gets the milliseconds component. |
Integer | DayOfWeek | Gets the day of the week. |
Integer | DayOfYear | Gets the day of the year. |
Long | Ticks | Gets the number of 100-nanosecond ticks that represent the date and time. |
Visual Basic .NET aims to please. If, by some incredible chance, none of the preceding functions or properties meet your important date-processing needs, one of the methods listed in the next table might be just the ticket. To use these methods, code the name of a DateTime object, a period, the method name, and then (in parentheses) any required arguments. Both of the following statements, for example, add seven days to the DateTime variable dtmDateDue. To subtract an interval, use an Add method and specify a negative amount.
dtmDateDue.Add(TimeSpan.FromDays(7)) dtmDateDue.AddDays(7)
The ToLocalTime and ToUniversalTime methods warrant a bit of additional explanation. By default, the starting point for all DateTime values is midnight, Coordinated Universal Time. Using this starting point eliminates endless confusion when computers in different time zones exchange dates, particularly in real time over a network.
The fact that dates on your computer are actually in UTC is almost never apparent because all the standard date functions automatically convert UTC to your local time zone, based on settings in the Windows Control Panel. This behind-the-scenes step eliminates any need to use the ToLocalTime and ToUniversalTime methods in ordinary software applications. However, if you do find a need to make these conversions, the necessary methods are ready and waiting.
Result Type | Member | Description |
---|---|---|
DateTime | Add | Adds the value of a given TimeSpan instance. |
DateTime | Subtract | Subtracts the value of a given TimeSpan instance. |
DateTime | AddYears | Adds the specified number of years. |
DateTime | AddMonths | Adds the specified number of months. |
DateTime | AddDays | Adds the specified number of days. |
DateTime | AddHours | Adds the specified number of hours. |
DateTime | AddMinutes | Adds the specified number of minutes. |
DateTime | AddSeconds | Adds the specified number of seconds. |
DateTime | AddMilliseconds | Adds the specified number of milliseconds. |
DateTime | AddTicks | Adds the specified number of ticks. |
DateTime | ToLocalTime | Converts the current coordinated universal time (UTC) to local time. |
DateTime | ToUniversalTime | Converts the current local time to coordinated universal time (UTC). |
Integer | CompareTo | Compares the current DateTime object to another and returns -1, 0, or +1, depending on their relative values. |
Integer | Equals | Indicates whether another variable points to the same DateTime object as the current variable. |
Long | ToFileTime | Converts the DateTime value to the format of the local system file time. |
String | ToLongDateString | Formats the DateTime value as specified by the operating system’s Long Date setting. |
String | ToLongTimeString | Formats the DateTime value as specified by the operating system’s Long Time setting. |
String | ToShortDateString | Formats the DateTime value as specified by the operating system’s Short Date setting. |
String | ToShortTimeString | Formats the DateTime value as specified by the operating system’s Short Time setting. |
String | ToString | Formats the DateTime value as an equivalent string. |
Double | ToOADate | Converts the value of this instance to the equivalent OLE Automation date. |
String handling is a major part of the processing that goes on in most Web pages. The simple reason is that most data consists of strings.
Previous sections described how to define string constants, literals, and variables; concatenate strings; and assign the value of a string expression to another. These are worthwhile operations, but they don’t address common requirements such as the need to split, join, and otherwise modify string data. For such operations, Visual Basic .NET provides the functions listed in the following table.
Visual Basic .NET String Handling Functions | ||
---|---|---|
Result Type | Function | Description |
Integer | StrComp | Compares two strings and returns the result. |
Long | Len | Returns the number of characters in a string or the number of bytes required to store a variable. |
Long | InStr | Returns the position of one string within another. |
Long | InStrRev | Returns the position of one string within another, searching from the end of string. |
Char | GetChar | Returns the character from the specified index in the supplied string. |
String | Mid | Returns a specified number of characters from a specified position within the argument string. |
String | Left | Returns a specified number of characters from the left side of a string. |
String | Right | Returns a specified number of characters from the right side of a string. |
String | Ltrim | Returns the argument string with leading spaces removed. |
String | Rtrim | Returns the argument string with trailing spaces removed. |
String | Trim | Returns the argument string with leading and trailing spaces removed. |
String | LCase | Converts the argument string to lowercase. |
String | UCase | Converts the argument string to uppercase. |
String | StrConv | Converts the argument string to a different case or character width. |
String | StrReverse | Reverses the order of the characters in the argument string. |
RSet | Returns the argument string with spaces added at the beginning, so that the string is a specified length and will be right-aligned with other strings of the same length. | |
String | LSet | Returns the argument string with spaces added at the end, so that the string is a specified length and will be left-aligned with other strings of the same length. |
String | Replace | Replaces one substring with another a specified number of times. |
String | Space | Returns a specified number of spaces. |
String | StrDup | Returns the argument character repeated a specific number of times. |
String | String | Returns a repeating character string of the length specified. |
Like all previous versions of Visual Basic, Visual Basic .NET supports arrays. An array, in this sense, is a series of variables, each identified by the same name but a different index number. Arrays make it easy for a program to loop through and process each variable the array contains.
Unlike previous versions of Visual Basic, Visual Basic .NET supports arrays not with its own built-in code, but through the .NET Framework’s System.Array object. This change means, for example, that when you define an array in Visual Basic .NET, you’re actually defining a .NET System.Array object. When you write traditional Visual Basic statements and expressions that process the array, Visual Basic .NET works behind the scenes and invokes System.Array properties and methods.
The fact that Visual Basic .NET implements arrays as .NET objects makes it simple to pass arrays among Visual Basic .NET modules, modules written in different programming languages, and .NET objects and interfaces of all kinds. Of course, this ease comes at a price; compared to previous versions, there are quite a few differences in the way Visual Basic .NET handles arrays.
The statement that defines a normal array hasn’t changed unless you’re accustomed to working with VBScript. The following statement, for example, defines an array of 12 integers named Month:
Dim Month(12) As Integer
In Visual Basic .NET, the following forms of declaration are also permissible. All three statements produce the same results, except that the last statement also puts values into the array.
Dim Month() As Integer = New Integer(12) {} Dim Month() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
Visual Basic allocates memory for all possible elements at the time you define an array. Therefore, don’t make arrays any larger than necessary.
If you’re accustomed to VBScript, you’re probably not accustomed to specifying the As keyword followed by a data type. This data type applies to each element of the array. Given that all other variable declarations require data types, however, the need to specify a data type for arrays should be no surprise. The permissible data types include
Any of the fundamental data types
Any structure
Any object class
When an array’s data type is Object, its elements can contain different kinds of data (objects, strings, numbers, and so forth).
In earlier versions of Visual Basic, you could define arrays that started with a subscript other than zero. This is no longer possible. Another difference is that when you code a statement such as
Dim Month(12) As Integer
Visual Basic .NET creates an array with 12 elements (the number you specified) subscripted 0 through 11. Earlier versions created 13 elements subscripted 0 through 12. If you try to access Month(12) in your code, Visual Basic .NET will throw a fit (oh, all right: an exception).
Visual Basic .NET arrays can have from one to 60 dimensions. The number of dimensions determines the array’s rank. An array of rank 3 would have three dimensions and its index would have three subscripts, as in cubicle(2, 4, 6). Most arrays have one dimension, and arrays of more than three dimensions are extremely rare.
All Visual Basic .NET arrays are variable-length, which doesn’t mean Visual Basic .NET automatically creates array elements when you access an out-of-bounds subscript. It does mean you can use the ReDim statement on any array whenever you want. The only restrictions are as follows:
You can’t use the ReDim statement to initially declare an array. Use Dim to declare the array and ReDim to modify it.
You can change the length of any dimension you want, but you can’t change the data type or the number of dimensions.
If you want to preserve existing data in the array, you can resize only the last dimension.
The following statement, for example, would expand the length of the Month table from 12 to 24. It would then support subscripts 0 through 23. It doesn’t matter which form of the Dim statement you used when you declared the array.
ReDim Preserve Month(24)
Whenever your code executes a ReDim statement, it first creates a completely new array, then copies over any existing array elements, and then deletes the first array. This process is expensive enough, in terms of resources, that you should avoid executing ReDim statements often. For example, don’t ReDim an array one element larger every time you want to store a value.
The fact that Visual Basic .NET array variables point to a System.Array object has the following implications:
An array variable that you declare in your ASP.NET page is actually a pointer to an object that contains the array’s rank, length, and element information.
Arrays have the same data type only if they have the same rank and the same element data type.
When you assign one array to another, Visual Basic .NET copies only the pointer. Consider, for example, the following block of statements:
Dim strHomeTeam() As String = {"Xavier","Yves","Zebediah"} Dim strVisitors() As String = {"Abby","Bryony","Cleo"} strHomeTeam = strVisitors strVisitors(0) = "Maeko"
After Visual Basic .NET executes these statements, both strVisitors(0) and strHomeTeam(0) will equal Maeko because the statement on line 3 makes strHomeTeam point to the same table object as strVisitors. The table object that strHomeTeam originally addressed was lost.
When you assign one array variable to another, Visual Basic .NET will enforce the following rules during compilation and at run time:
Either both arrays must have reference type elements (that is, objects) or both arrays must have value type elements (that is, integers, strings, and other elementary data types).
If both arrays have value type elements, the element data types must be exactly the same. The following generates an error:
Dim lngNumbers(10) As Long Dim strLetters(10) As String strLetters = lngNumbers
If both arrays have reference type elements, there must be a widening conversion from the source element type to the destination element type.
The rank (number of dimensions) of the source and destination arrays must be the same.
Although the ranks of the two arrays must be equal, the dimensions don’t. The length of any dimension in the destination array can change.
Like older versions of Visual Basic, Visual Basic .NET provides the array-related functions listed in the next table. The Ubound function in particular is worth noting because it always returns an up-to-date value for the maximum subscript of a table. Suppose, for example, that you defined the following table:
Dim strNames As String = {"Bill", "Mary", "Tom", "Wendy"}
If you assumed elsewhere in your code that this table contained four elements, the code would malfunction if some other part of your code changed the size of the array by using a ReDim or assignment statement. It’s much better to assume that the array contains Ubound(strNames) + 1 elements numbered 0 through Ubound(strNames).
Result Type | Function | Description |
---|---|---|
Array | Filter | Returns a subset of a string array containing only those elements that contain (or don’t contain) a specified string. |
Array | Split | Converts a delimited string into a one-dimensional array, based on the specified delimiter. |
Boolean | IsArray | Indicates whether a variable is an array. |
Long | Lbound | Returns the smallest available subscript for the indicated dimension of an array. In Visual Basic .NET, this is always zero. |
Long | Ubound | Returns the largest available subscript for the indicated dimension of an array. |
String | Join | Converts an array into a delimited string, inserting the specified delimiter between the values of each former array element. |
Because Visual Basic .NET arrays inherit from the Array class in the System namespace, you can use System.Array methods and properties on any Visual Basic .NET array. The second statement in the following example displays the array’s rank. The third sorts the array based on the values in its elements.
Dim strAnimals() As String = {"Crocodile","Bison","Aardvark"} Response.Write(strAnimals.Rank) Array.Sort(strAnimals)
The following table lists a number of useful functions that the System.Array object provides. Note that these are methods of the System.Array object itself, and not of individual arrays. You specify the array you want to process as an argument.
Common System.Array Public Static Methods | |||
---|---|---|---|
Method Type | Result Type | Method | Description |
Function | Integer | Array.BinarySearch | Searches a one-dimensional sorted array for a value, using a binary search algorithm. |
Function | Integer | Array.IndexOf | Sequentially searches all or part of a one-dimensional array for a given value, starting from the lowest applicable index. |
Integer | Array.LastIndexOf | Sequentially searches all or part of a one-dimensional array, starting from the highest applicable index. | |
Sub | Array.Clear | Sets a range of array elements to Nothing. | |
Sub | Array.Copy | Copies a section of one array to another and performs type downcasting as required. | |
Sub | Array.Reverse | Reverses the order of elements in all or part of a one-dimensional array. | |
Sub | Array.Sort | Sorts the elements of a one-dimensional array. |
To look up the calling sequence for these methods, as well as for properties and methods in the next two tables, search the MSDN Web site (msdn.microsoft.com/library) for the term NET Framework Class Library and then search within the results for the terms System, Array Class, and Members.
The "Common System.Arrray Properties" table lists the Rank property (already discussed) and the Length property, which returns a count of elements in all dimensions of an array. For most Visual Basic Web developers, the Length property of an array is something to avoid. To see why, consider the following array:
Dim TwoDim(10, 20)
The expression TwoDim.Length returns 231, which is the product of 11 × 21. The expressions Ubound(TwoDim, 1) and Ubound(TwoDim, 2), which return 10 and 20, are far more useful.
Common System.Array Properties | ||
---|---|---|
Result Type | Method | Description |
Long | Length | Returns the total number of elements in all dimensions of an array. |
Long | Rank | Returns the rank (number of dimensions) of an array. |
Each Visual Basic .NET array inherits the System.Array methods listed in the "Common System.Array Methods" table.
Common System.Array Methods | |||
---|---|---|---|
Method Type | Result Type | Method | Description |
Function | Array | Clone | Creates a new array that points to the same elements as the original array. |
Function | Boolean | Equals | Determines whether two object instances are equal. |
Function | Integer | GetLength | Gets the number of elements in the specified dimension of an array. This value exceeds by one the number of elements available to Visual Basic .NET. |
Function | Integer | GetLowerBound | Gets the lower bound of the specified dimension in the array. This is always zero. |
Function | Integer | GetUpperBound | Gets the upper bound of the specified dimension in the array. This value equals the number of elements available to Visual Basic .NET. |
Function | Type | GetType | Gets the type of an array. Compare the result to an expression such as GetType(String). |
Function | Array Type | GetValue | Gets the values of the array elements at the specified indexes. |
Sub | SetValue | Sets the specified array element to the specified value. | |
Sub | CopyTo | Copies all the elements of a one-dimensional array to another starting at a specified destination index. |
To use these methods, you append their names to the name of the array you want them to process. Here’s an example:
strVisitors.CopyTo(strHomeTeam,0)
This statement copies all the elements of the strVisitors array into the strHomeTeam array, starting at position 0 of the strHomeTeam array. Unlike the assignment statement strHomeTeam = strVisitors, the CopyTo method actually copies each element of the source array. The source and destination array variables don’t end up being aliases of the same physical table. However, the CopyTo method has its own quirks:
It works only on one-dimensional arrays.
It can’t resize the destination array.
At least in early versions, and despite the previous statement, it has the unfortunate effect of adding one empty element to the end of the destination array.
For the most part, the remaining methods perform functions that the Visual Basic .NET functions listed in the previous table also provide. In general, the Visual Basic .NET functions are more reliable and easier to use.
Arrays, which have been features of most programming languages since the early years of computing, provide an excellent way to process collections of data in a repetitive manner. For some jobs, however, the inherent structure of arrays makes them a poor fit. This is particularly true of collections that contain a continually variable number of items and collections where the natural identifier is alphabetic rather than numeric.
VBScript provides a Scripting.Dictionary object that meets these needs to a large extent. Basically, a programmer working in VBScript can add, update, and delete items in a Scripting.Dictionary object at will, and each item has an alphanumeric identifier. This object is often useful when using an array would be awkward, but it doesn’t keep its entries in order by key value. In other words, it doesn’t accommodate situations where you need a variable number of numeric keys or where you need alphanumeric keys kept in order.
To resolve these issues in Visual Basic .NET, Microsoft chose not to implement a .NET version of the Scripting.Dictionary object, but to implement the following objects instead:
ArrayList. This object stores a collection of values in a variable-length list and identifies them by numeric position. An ArrayList containing 10 items, for example, would identify them as 0–9. If you deleted the fifth item, the remaining items would be 0–8.
Hashtable. This object holds a collection of string keys and associated values organized by a hash code of the key. (A hash code is an arbitrary value calculated from some other value such as, in this case, the item key.) A Hashtable stores the keys in random order and is thus the most comparable of these objects to the Scripting.Dictionary.
SortedList. This object works very much like a Hashtable, except that it keeps its keys in alphanumeric order. As with the Hashtable, you can access the values in a SortedList by alphanumeric key. As with the ArrayList, you can also access the values by numeric position. Finally, you can access the key values in a SortedList by numeric position as well.
Queue. This object stores a collection of items and returns them in first-in, first-out order.
Stack. This object stores a collection of items and returns them in last-in, first-out order.
Although tables and collections can both store structures and objects, the ADO.NET DataTable is much better suited to handling data records. For more information about DataTables, refer to Chapter 7.
To add one of these objects to your Web page, simply declare it as shown:
Dim arlNames As New ArrayList Dim htbNames As New Hashtable dim stlNames As New SortedList dim queNames As New Queue dim stkNames As New Stack
The table ".NET Collection Methods" summarizes the methods available for each object type, and ".NET Collection Properties" summarizes the properties. To the extent possible, Microsoft has implemented the same properties and methods for all five collections. All five objects, for example, have a Count property that reports the number of items the object currently stores.
.NET Collection Methods | ||||||
---|---|---|---|---|---|---|
Method | Description | Array List | Hash table | Sorted List | Queue | Stack |
Add | Adds an entry to the collection. | X | X | X | – | – |
BinarySearch | Uses a binary search to locate a specific element. | X | – | – | – | – |
Clear | Removes all elements from the collection. | X | X | X | X | X |
Clone | Creates a shallow copy of the collection. | X | X | X | X | X |
Contains | Determines whether an element is in the collection. | X | X | X | X | X |
ContainsKey | Determines whether the collection contains a specific key. | – | X | X | – | – |
ContainsValue | Determines whether the collection contains a specific value. | – | X | X | – | – |
CopyTo | Copies all or part of a collection to a one-dimensional array. | X | X | X | X | X |
Dequeue | Removes and returns the object at the beginning of the Queue. | – | – | – | X | – |
Enqueue | Adds an object to the end of the Queue. | – | – | – | X | – |
GetByIndex | Gets the value at the specified index of the SortedList. | – | – | X | – | – |
GetKey | Gets the key at the specified index of the SortedList. | – | – | X | – | – |
GetKeyList | Gets the keys in the SortedList. | – | – | X | – | – |
GetObjectData | Implements the ISerializable interface and returns the data needed to serialize the Hashtable. | – | X | – | – | – |
GetRange | Returns an ArrayList that represents a subset of the elements in the source ArrayList. | X | – | – | – | – |
GetType | Gets the Type of the current instance. | X | X | X | X | X |
GetValueList | Gets the values in the SortedList. | – | – | X | – | – |
IndexOf | Returns the zero-based index of the first occurrence of a value in the ArrayList or in a portion of it. | X | – | – | – | – |
IndexOfKey | Returns the zero-based index of the specified key in the SortedList. | – | – | X | – | – |
IndexOfValue | Returns the zero-based index of the first occurrence of the specified value in the SortedList. | – | – | X | – | – |
Insert | Inserts an element into the ArrayList at the specified index. | X | – | – | – | – |
InsertRange | Inserts the elements of a collection into the ArrayList at the specified index. | X | – | – | – | – |
LastIndexOf | Returns the zero-based index of the last occurrence of a value in the ArrayList or in a portion of it. | X | – | – | – | – |
Peek | Returns the object at the beginning or top of the collection without removing it. | – | – | – | X | X |
Pop | Removes and returns the object at the top of the Stack. | – | – | – | – | X |
Push | Inserts an object at the top of the Stack. | – | – | – | – | X |
Remove | Removes an entry from the collection. | X | X | X | – | – |
RemoveAt | Removes the element at the specified index of the collection. | X | – | X | – | – |
RemoveRange | Removes a range of elements from the ArrayList. | X | – | – | – | – |
Reverse | Reverses the order of the elements in the ArrayList or a portion of it. | X | – | – | – | – |
SetByIndex | Replaces the value at a specific index in the SortedList. | – | – | X | – | – |
SetRange | Copies the elements of a collection over a range of elements in the ArrayList. | X | – | – | – | – |
Sort | Sorts the elementsin the ArrayList or a portion of it. | X | – | – | – | – |
ToArray | Copies collection elements to a new array. | X | – | – | X | X |
TrimToSize | Sets the capacity to the actual number of elements in the collection. | X | – | X | – | – |
The Add method adds an item to an ArrayList, Hashtable, or SortedList collection.
For ArrayLists, the Add method accepts only a value; the ArrayList increases the size of the collection by one and adds the new entry at the end. Here are two examples:
arlNames.Add("Abrienda") intPos = arlNames.Add("Bryony")
After executing the second statement, the variable intPos contains the new entry’s index value.
For Hashtables and SortedLists, the Add method expects both a key and a value.
A Hashtable collection adds the item in random order.
A SortedList collection adds it in sequence by key value.
For Hashtables and SortedLists, the following statements are equivalent:
myCollection.Add("Name", "Elvina") myCollection("Name") = "Elvina"
The Remove method removes one element from an ArrayList, Hashtable, or SortedList collection, based on a method argument you supply. An ArrayList removes the first element with a value that matches the Remove argument. Hashtables and SortedLists remove the element with a key value that matches the Remove argument.
The RemoveAt method removes an element of an ArrayList or SortedList collection based on its numeric index. The RemoveRange method removes a range of elements from an ArrayList.
For a Queue collection, the Enqueue and Dequeue methods add and remove items. For a Stack collection, the Push and Pop methods do the same.
Method | Description | Array List | Hash table | Sorted List | Queue | Stack |
---|---|---|---|---|---|---|
Capacity | Gets or sets the number of elements the collection can contain. | X | – | X | – | – |
Count | Gets the number of elements the collection actually contains. | X | X | X | X | X |
IsFixedSize | Gets a value indicating whether the collection has a fixed size. | X | X | X | – | – |
IsReadOnly | Gets a value indicating whether the collection is read-only. | X | X | X | X | X |
Item | Gets or sets the element at the specified index or key. | X | X | X | – | – |
Keys | Gets a collection of keys in the source collection. | – | X | X | – | – |
Values | Gets a collection of values in the source collection. | – | X | X | – | – |
For more information about any of these objects, their properties, or their methods, search the MSDN Web site (msdn.microsoft.com/library) for the term System.Collections.
In Visual Basic .NET, objects no longer have default properties. Instead, you must spell out the name of any property you want to use. Suppose, for example, your Web page contains the following Web Server Control:
<asp:label id="lblMessage" runat="server" />
You can’t assign a value to this control by coding a statement such as the following:
lblMessage = "Pounding the computer won't help."
The variable lblMessage doesn’t contain the label control directly; instead, it contains a pointer to the label control object. The preceding statement tries to replace that pointer, and because a string value can’t point to an object, it will produce a type mismatch error. Here’s the correct statement:
lblMessage.Text = "Pounding the computer won't help."
Occasionally, Visual Basic .NET will let you retrieve the value of an object without specifying a property name—not because some objects have default properties but because type conversion happens to return the value you want. Remembering the cases where this works is usually harder than coding the exact property name you want.
Visual Basic .NET (and, for that matter, ASP.NET) is perfectly capable of using Component Object Model (COM) objects, very much as classic ASP pages have done for years. Here’s an example:
Dim cnOrderDb As Object cnOrderDb = Server.CreateObject("ADODB.Connection")
Note the absence of a Set command at the beginning of the second statement. Set commands are neither required nor supported in Visual Basic .NET.
There is, however, a catch. Classic ASP pages use a so-called threading model called Single Threaded Apartment (STA). This model states that among all objects in a given apartment (and the apartment in this case is the Web page) only one object can execute at any given time. If two or three objects are all ready to execute, the first must end before the second can start, and so forth.
ASP.NET pages use the Multiple Threaded Apartment (MTA) threading model. If two or more objects are ready to execute, ASP.NET starts executing all of them simultaneously. This capability improves overall performance, but it requires special features in the implementation of each object. Under STA, for example, an object never has to worry about another object taking exclusive control of a resource or updating information unexpectedly. Under MTA, every object has to take these precautions. Otherwise, that object or another object might fail or produce incorrect results.
Any COM objects that a programmer created in Visual Basic 6 use STA threading. Any ASP.NET page that uses one of these objects will require the AspCompat="True" attribute.
Fortunately, ASP.NET supports an operating mode that executes STA objects safely. To request this mode, simply code the AspCompat="True" attribute in a <%@Page> tag. Here’s an example:
<%@Page AspCompat="True" Language="VB"%>
Setting this attribute to True results in a slight performance penalty, so code it only if necessary.
Visual Basic .NET preserves support for all logic statements that worked in previous versions of Visual Basic. What a refreshing change! There are, however, only two such statements: If and Select. Here’s the general format of an If statement:
If [condition] Then [Your statements go here] Else [Your statements go here] End If
As always, the Else and its following statements are optional. In a change from previous versions, though, the End If terminator and the line ending after Then are required. The compiler will no longer accept statements such as
If txtAge.Text = "" Then lblAgeMsg.Text = "You must enter an age."
The If...ElseIf format is still supported as well, which is useful when you need to test a series of conditions until you find one that’s True. Here’s an example:
If strName = "Uang" Then strGift = "Bus" ElseIf strName = "Uba" Then strGift = "Car" ElseIf strName = "Uday" Then strGift = "Truck" ElseIf strName = "Ugo" Then strGift = "Bus" ElseIf strName = "Ujana" Then strGift = "Car" End If
In such cases, the ElseIf form can be much easier than a more typical nesting of If...Else...End If statements.
The Case statement provides another way to test a series of conditions until one is true. The Case statement has this syntax:
Select Case [expression] Case [expression] Case [expression] Case Else End Select
You can code as many Case statements as you like, and the Case Else statement is optional. Visual Basic .NET uses the Case expressions of Visual Basic 6, which are more flexible and powerful than those available in VBScript. The following statement, for example, is completely valid:
Select lngAge Case < 1 lblDesc.Text = "Infant" Case 1 To 5 lblDesc.Text = "Toddler" Case 6, 8 lblDesc.Text = "Even Child" Case 7, 9 lblDesc.Text = "Odd Child" Case 10 To 12 lblDesc.Text = "Pre-teen" Case Else lblDesc.Text = "Trouble" End Select
In the true spirit of progress, the following logical functions are obsolete. Visual Basic .NET no longer supports them. Goodbye.
IsEmpty, IsMissing, IsNull, IsObject
Visual Basic .NET does, however, support all the logical functions listed in the following table. Instead of using one of the stricken functions listed above, use IsDbNull for database fields and IsNothing for everything else.
Result Type | Function | Description |
---|---|---|
Object | Choose | Selects and returns a value from a list of arguments. |
Object | IIf | Returns one of two objects, depending on the evaluation of an expression. |
Boolean | IsDbNull | Returns a Boolean value indicating whether an expression evaluates to the System.DBNull class. |
Boolean | IsError | Returns a Boolean value indicating whether an expression is an error value. |
Boolean | IsNothing | Returns a Boolean value indicating whether an expression has no object assigned to it. |
Boolean | IsNumeric | Returns a Boolean value indicating whether Visual Basic .NET can convert an expression to a number. |
Boolean | IsReference | Returns a Boolean value of True if the expression represents an Object variable that currently has no object assigned to it; otherwise, it returns False. |
String | Partition | Returns a String indicating where a number occurs within a calculated series of ranges. |
Object | Switch | Evaluates a list of expressions and returns a Variant value or an expression associated with the first expression in the list that’s True. |
The Choose function expects to receive an index value followed by a series of expressions. If the index value is 1, Choose evaluates and returns the first expression. If the index is 2, Choose evaluates the second expression, and so forth. Here’s an example:
strVolunteer = Choose(intNum, "Pablo", "Quinta", "Radwan")
The IIf function returns one of two expressions depending on whether an expression is True or False. Here’s a case in point:
strSize = IIf(intWaist > 30, "Large", "Small")
The Partition function is a weird one. Here are its syntax and a typical statement:
Partition(Number, Start, Stop, Interval) Partition(lngAge, 0, 99, 20)
When Visual Basic .NET evaluates this statement, it sets up a series of numeric ranges such as the following:
Range Name | Low Value | High Value |
"0: 19" | 0 | 19 |
"20: 39" | 20 | 39 |
"40: 59" | 40 | 59 |
"60: 79" | 60 | 79 |
"80: 99" | 80 | 99 |
The ranges start at the Start value and increase by Interval until they reach the Stop value. Visual Basic .NET then determines which range the given Number falls within and returns the name of that range as a string. For example, after Visual Basic .NET executes the following expression, strBracket will contain "20: 39".
strBracket = Partition(25, 0, 99, 20)
The Switch function interprets a list of paired expressions and values. If the first argument you pass to Switch is True, Switch evaluates and returns the second argument. If the third argument is true, Switch returns the fourth argument, and so forth. Here’s an example:
strCity = Switch(strEntree = "Kidney Pie", "London", _ strEntree = "Wiener Schnitzel", "Munich", _ strEntree = "Kielbasa", "Warsaw", _ strEntree = "Chop Suey", "San Francisco")
If another part of your code set strEntree to "Wiener Schnitzel" (the third argument), this statement will assign the value "Munich" (the fourth argument) to the variable strCity, and so on.
Visual Basic .NET supports most of the same looping and logic constructs, itemized in the next table, that Visual Basic has supported for years. The GoTo and GoSub statements are notable omissions. Another change involves the While... Wend loop, which is now a While... End While loop.
Visual Basic .NET supports the same subroutine and function features as other versions of Visual Basic. For your reference, the required syntaxes appear here:
Sub name [(argument As type, ...)]
[statements]
[Exit Sub]
[statements]
End Sub
Function name [(argument As type, ...)] As type
[statements]
[Exit Function]
[statements]
name = expression
[statements]
return expression
End Function
The difference between a Sub and a Function is that only a Function returns a value. You can set the return value of a Function in two different ways:
You can assign a value to the function name as if it were a variable:
Function Whatever(astrName As String) As String [statements] Whatever = "This is the end." End Function
You can code a Return statement that includes an expression:
Function Whatever(astrName As String) As String
[statements]
Return "This is the end."
End Function
The choice of method is up to you, and it will probably depend on the structure of your code. The Return statement immediately exits the function, but assigning a value to the function name doesn’t. If you invoke a function without using the return value in an expression, Visual Basic .NET discards it. The following invocation, for example, discards the return value:
Whatever("Hazel")
When you call a subroutine, Visual Basic .NET requires parentheses around the arguments. Thus, the first of the following statements will produce a compiler error. The second statement is correct.
Response.Write "This will happen often." Response.Write("This will happen often.")
By default, past versions of Visual Basic passed all subroutine and function arguments by reference (ByRef). This means the subroutine or function received a pointer to the actual argument.
By default, Visual Basic .NET subroutines and functions receive arguments by value (ByVal). Visual Basic .NET copies the value in the calling procedure and gives the subroutine or function the address of the copy. This operation has two consequences:
Copying each argument value consumes extra resources on the server.
If a subroutine or function modifies the value of an argument passed by value, the variable in the calling procedure remains unchanged.
To override the default and make a subroutine or function receive arguments by reference, code ByRef just before the argument name. Here’s an example:
Function Whatever(ByRef astrName As String) As String
Visual Basic .NET supports recursive subroutine and function calls, meaning that a subroutine or function can call itself any number of times. However, deeply nesting such calls can lead to stack or memory overflow. Don’t call a subroutine or function recursively more than a few times without exiting.
The syntax for defining a class has also changed. Here’s the new form:
Public Class name [ Implements interfacename ] Public Property propertyname As type Get propertyname = InternalValue End Get Set InternalValue = propertyname End Set End Property Private Sub name [(argument, ...)] [statements] End Sub Public Function name [(argument, ...)] [statements] End Function End Class
Note the Get...End Get and Set...End Set sequences within the property definition. These are both required unless you code ReadOnly or WriteOnly as follows:
Public ReadOnly Property Count As Long Public WriteOnly Property Count As Long
If you code ReadOnly, other programs can retrieve the property value, but they can’t change it. A ReadOnly property must include a Get...End Get block, but can’t contain a Set...End Set block.
If you code WriteOnly, other programs can change the property value, but they can’t retrieve it. A WriteOnly property must include a Set...End Set block, but can’t contain a Get...End Get block.
In a Get procedure, you return a value to the calling procedure by assigning it to the property name. Here’s an example:
Public Property Height As Long Get Height = lngHeight End Get End Property
In a Set procedure, there are two different ways to retrieve the value that the calling procedure sent. If you coded arguments on the Set statement, you read those arguments as follows:
Set (alngHeight as long) mlngCurHeight = alngHeight End Set
If you didn’t code arguments, then you read the implicit argument Value:
Set mlngCurHeight = Value End Set
Although the examples in this chapter specify Public access, all the modifiers listed in the table below are available. In practice, most access modifiers are either Public (the property or method is accessible outside the current class) or Private (the property or method is accessible only within the current class). The default is Private.
Visual Basic .NET Access Modifiers | |
---|---|
Access Modifier | Description |
Public | The entity will be available to all other entities. |
Private | The entity will be available only to entities within the context of its declaration, including any nested entities. |
Protected | The entity will be available only within its own class or a derived class. |
Friend | The entity will be available only within the program that contains its declaration. |
Protected Friend | The entities will have the union of Protected and Friend accessibility. |
Shadows | Indicates that this class shadows (that is, uses the same name as) an identically named programming element in a base class, making the element in the base class un-available. |
MustInherit | Indicates that the class contains methods that a deriving class must implement. |
NotInheritable | Indicates that no further inheritance of the current class is allowed. |
interfacename | The name of the interface this class implements. |
Until now, if you didn’t want a serious error to terminate your Visual Basic code, the only alternative was to precede the risky statement with an On Error Resume Next statement. Doing so invoked an operating mode where serious errors updated an Err object rather than terminating the ASP.NET page, making it the Web developer’s responsibility to check the status of the Err object after each statement. To resume normal error checking, the developer coded On Error GoTo 0.
These facilities are still present in Visual Basic .NET, but so is a much better approach called structured exception handling. Using this approach involves coding the following structure:
Try [risky statements] Catch [optional filter] [statements] Catch [optional filter] [statements] ... Finally [statements] End Try
Visual Basic .NET executes statements after the opening Try statement and before the first Catch statement normally, unless and until an error occurs. If an error does occur, Visual Basic .NET examines each Catch statement until it finds one with a condition that matches that error.
If a Catch statement contains a matching condition, control transfers to the first line of code in that Catch block. If no Catch statement contains a matching condition, the search proceeds to the Catch statements of any Try...End Try block that contains the block where the exception occurred.
This process continues until Visual Basic .NET finds a matching Catch block or no more Try...End Try blocks remain. If no blocks remain, the error asserts itself.
Visual Basic .NET always executes the code in the Finally section last, regardless of whether it executed any Catch block code. Code in this section usually closes files, releases objects, and performs other kinds of cleanup.
You can code Catch block filters in either of two ways. In the first, Visual Basic .NET filters errors based on the class of the exception. The following is an example.
Try ["Try" statements] Catch e as ClassLoadException [error handling statements] Finally [cleanup statements] End Try
If a ClassLoadException occurs while Visual Basic .NET is executing a statement you coded between Try and the first Catch, Visual Basic .NET executes the code within the specified Catch block (and then the code in the Finally block). You can write as many of these Catch statements (and thereby catch as many different kinds of exceptions) as you want.
Knowing what exception classes to catch is less of a problem than you might suspect. In many cases, the reason you’re coding the Try block is that your Web page has already blown up for a condition you’d rather handle internally. In this case, you can copy the name of the exception class out of the error message and paste it into your code. Otherwise, the documentation for each object in the .NET Framework lists the types of exceptions that are possible.
The second way of coding Catch block filters is to code any conditional expression. One common use of this form of Catch filter is to test for specific error numbers, as shown in the following code:
Try y = 0 x /= y Catch ex As Exception When y = 0 x = 0 lblError.Text = "Divide by zero" Finally [cleanup statements] End Try
To catch any and all exceptions, code:
Catch ex as Exception
As you might have noticed, Catch statements receive an Exception object. Some exceptions return specialized objects, but most of them inherit the properties shown in the table below. The majority of exceptions use the generic Exception object and return exactly these properties. The Message property is generally the most useful.
.NET Exception Object Properties | ||
---|---|---|
Type | Name | Description |
String | HelpLink | Gets or sets a link to the Help file associated with this exception. |
Exception Object | InnerException | Gets a reference to the inner exception. |
String | Message | Gets the error message text. |
String | Source | Gets or sets a string containing the name of the application or the object that causes the error. |
String | StackTrace | Gets the stack trace, which identifies the location in the code where the error occurs. |
MethodBase Object | TargetSite | Gets the method that throws this exception. |
If the need arises, you can also throw your own exceptions. The syntax is
Throw New System.Exception()
Note that this syntax creates a new Exception object and passes it as an argument. Inside the parentheses, you can specify
Nothing, to pass an exception with default properties.
A string value that contains an error message.
A string value and another exception object, which gives the next higher Catch handler your error message, as well as a reference to another error you detected.
The procedure that follows will develop a simple Web page that will add, subtract, multiply, or divide any two numbers the visitor types into a pair of text boxes. Of course, if the visitor enters a value that’s not a number, the calculation will fail. In this case, the Web page itself will display the error message rather than let ASP.NET display the system error message page. The graphic below shows this Web page in action:
Follow this procedure if you wish to create this Web page. If you’d rather look at the finished code, open the calc.aspx page in the ch05 folder of the sample files.
Create a new, blank Web page containing an @ Page directive, then a code declaration block, then the usual HTML tags.
Give the Web page a title by coding <title>Bomb-Proof Calculator</title> in the <head> section and <h1>Bomb-Proof Calculator</h1> just after the <body> tag. Insert any page formatting statements, such a links to style sheet files, that you like.
Create a Web Form after the <h1></h1> heading. That is, add the following tags:
<form runat="server"> </form>
Create three paragraphs between the <form> and </form> tags. To do this, add three lines, each containing <p></p>.
Add two text boxes, named txtOp1 and txtOp2, to the first paragraph. The paragraph will then look like this:
<p> <asp:TextBox id="txtOp1" runat="server" /> <asp:TextBox id="txtOp2" runat="server" /> </p>
Add a drop-down list named ddlOper between the two text boxes. Make it offer choices of +, -, *, and /. Here’s the required code:
<asp:DropDownList id="ddlOper" runat="server"> <asp:ListItem>+</asp:ListItem> <asp:ListItem>-</asp:ListItem> <asp:ListItem>*</asp:ListItem> <asp:ListItem>/</asp:ListItem> </asp:DropDownList>
Add an equal sign and a label control named lblResult after the second text box. Here’s the code:
= <asp:label id="lblResult" runat="server" />
Add a Submit button to the second paragraph. The following code will suffice. The <p> and </p> tags are some of those you entered in step 4.
<p><asp:Button id="btnSub" Text="Submit" runat="server"/></p>
Add a Label control named lblMessage to the third paragraph. Here’s how the paragraph should look when you’re finished:
<p><asp:label id="lblMessage" runat="server" /></p>
Save the Web page as calc.aspx and load it into your browser by means of an http:// URL. You should find that it resembles the previous figure but does nothing when you click Submit.
Add a Page_Load subroutine to the code declaration block you created in step 1. This requires the following statements:
Sub Page_Load(sender As Object, e As EventArgs) End Sub
It would be pointless to perform a calculation the first time the Web page loads. The visitor, at that point, has had no opportunity to enter any numbers. Therefore, code an If statement that determines whether a postback is in effect. The Page_Load subroutine will then look like this:
Sub Page_Load(sender As Object, e As EventArgs) If Page.IsPostBack Then End If End Sub
Between the two statements you added in step 12, code a Select Case statement that performs the requested operation on the two numbers.
Select Case ddlOper.SelectedItem.Text Case "+" lblResult.Text = Cdbl(txtOp1.Text) + _ Cdbl(txtOp2.Text) Case "-" lblResult.Text = Cdbl(txtOp1.Text) - _ Cdbl(txtOp2.Text) Case "*" lblResult.Text = Cdbl(txtOp1.Text) * _ Cdbl(txtOp2.Text) Case Else lblResult.Text = Cdbl(txtOp1.Text) / _ Cdbl(txtOp2.Text) End Select
The expression ddlOper.SelectedItem.Text returns the text of the list box item that the visitor selects.
The four Case statements differentiate among the four possible values.
The statement following each Case statement converts the two text box values to Doubles, performs the requested calculation, and stores the result in the lblResult label object you created in step 7.
If you save the Web page at this point and try performing calculations, you should find that all goes well as long as you enter two numeric operands. If you make an invalid entry, however, the page will fail and display an error page like the one shown here.
Add a Try statement before the Select statement you added in step 13 and an End Try statement after the End Select statement.
After the End Select statement you added in step 13, add the Catch statement that appears in the following code.
Try
' Select statement from step 13
Catch ex as Exception
End Try
This Catch statement will catch all exceptions. If an exception occurs, the variable ex will point to a relevant exception object.
After the Catch statement you added in the previous step, enter a statement that copies the current error message to the Label control you created in step 9. Visual Basic .NET will execute this statement only if an exception occurs.
Catch ex as Exception lblMessage.Text = ex.Message End Try
Add the following statement after the End Select statement that terminates the Select Case block. This will erase any error message the lblMessage label control might contain.
lblMessage.Text = ""
The presence of this statement also proves that if an exception occurs, the rest of the code in the Try block doesn’t execute. If the rest of the code in the Try block did execute, this statement would wipe out the error message.
This completes the code for the calc.aspx page. Save the page and try running it again. You should no longer be able to bomb it by entering invalid values; the page will simply display an error message as shown in this graphic. The code listing for the entire page follows.
<%@Page Language="VB" Debug="True"%> <script runat="server"> Sub Page_Load(sender As Object, e As EventArgs) If Page.IsPostBack Then Try Select Case ddlOper.SelectedItem.Text Case "+" lblResult.Text = Cdbl(txtOp1.Text) + _ Cdbl(txtOp2.Text) Case "-" lblResult.Text = Cdbl(txtOp1.Text) - _ Cdbl(txtOp2.Text) Case "*" lblResult.Text = Cdbl(txtOp1.Text) * _ Cdbl(txtOp2.Text) Case Else lblResult.Text = Cdbl(txtOp1.Text) / _ Cdbl(txtOp2.Text) End Select lblMessage.Text = "" Catch ex as Exception lblMessage.Text = ex.Message End Try End If End Sub </script> <html> <head> <title>Bomb-Proof Calculator</title> <link rel="stylesheet" type="text/css" href="../normal.css"> </head> <body> <h1>Bomb-Proof Calculator</h1> <form runat="server"> <p> <asp:TextBox id="txtOp1" runat="server" /> <asp:DropDownList id="ddlOper" runat="server"> <asp:ListItem>+</asp:ListItem> <asp:ListItem>-</asp:ListItem> <asp:ListItem>*</asp:ListItem> <asp:ListItem>/</asp:ListItem> </asp:DropDownList> <asp:TextBox id="txtOp2" runat="server" /> = <asp:label id="lblResult" runat="server" /> </p> <p><asp:Button id="btnSub" Text="Submit" runat="server"/></p> <p><asp:label id="lblMessage" runat="server" /></p> </form> </body> </html>
This chapter explained the basic structure of Visual Basic .NET by examining the syntax and capabilities of its literals, variables, statements, operators, functions, and other elements. Although Visual Basic .NET is an easy programming language to learn, it’s also a broad and comprehensive language suitable for complex projects.
The need for Visual Basic to operate with the common language runtime has imposed a variety of changes on the language. For the most part, these changes are worthwhile and modernizing, but they do require study, even for experienced Visual Basic programmers.
The next chapter will introduce a number of database concepts and terms you’ll need for developing database-driven Web sites.
18.218.45.80