You can also define a variable by using the type name from the .NET class library. This approach produces identical variables. It’s also a requirement when the data type doesn’t have an alias built into the language. For example, you can rewrite the earlier example that used VB .NET data type names with this code snippet that uses the class library names: Dim ErrorCode As System.Int32 This code snippet uses fully qualified type names that indicate that the Int32 type is found in the System namespace (along with all of the most fundamental types). In Chapter 4, we’ll discuss types and namespaces in more detail. .......................................................................................................................... Data Type Changes from Visual Basic 6 Luckily for VB developers, the list of data types in .NET is quite similar to the data types from earlier versions. Some changes, however, were unavoidable:
Once you’ve created your variable you can freely assign values to them, as long as these values have the correct data type. Here’s the code that shows this two step process: ' Define variables. You can also assign a value to a variable in the same line that you create it. This feature is familiar to most C++ programmers, but it’s a new addition to VB .NET. Here’s an example that compresses four lines of code into two: Dim ErrorCode As Integer = 10 Visual Basic .NET is kind enough to let you use simple data types without initializing them. Numbers are automatically initialized to 0 and strings are initialized to an empty string (""). That means the following code will succeed in VB .NET: Dim Number As Integer ' Number now contains 0. ........................................................................................................................ What’s in a Name? Not the Data Type. You’ll notice that the preceding examples don’t use variable prefixes. Most Visual Basic and C++ programmers are in the habit of adding a few characters to the start of a variable name to indicate its data type. In .NET, this practice is discouraged, because data types can be used in a much more flexible range of ways without any problem, and most variables hold references to full objects anyway. In this book, variable prefixes aren’t used, except for web controls, in which it helps to distinguish lists, text boxes, buttons, and other common user interface elements. In your own programs, you should follow a consistent (typically companywide) standard that may or may not adopt a system of variable prefixes. ........................................................................................................................... ArraysArrays allow you to store a series of values that have the same data type. Each individual value in the array is accessed using one or more index numbers. It’s often convenient to picture arrays as lists of data (if the array has one dimension), or grids of data (if the array has two dimensions). Typically, arrays are laid out contiguously in memory. Visual Basic programmers will find that arrays are one of the most profoundly changed language elements. In seeking to harmonize .NET languages, Microsoft decided that all arrays must start at a fixed lower bound of 0. There are no exceptions. When you create an array in VB .NET, you simply specify the upper bound. ' Create an array with four strings (from index 0 to index 3). By default, if your array includes simple data types they are all initialized to default values (0, False, or "", depending on whether you are using some type of number, a Boolean variable, or a string). You can also fill an array with data at the same time that you create it. In this case, you don’t need to explicitly specify the number of elements, because .NET can determine it automatically. ' Create an array with four strings, one for each number from 1 to 4. The same technique works for multidimensional arrays, except that two sets of curly brackets are required: ' Create a 4 x 2 array (a grid with four rows and two columns). Figure 3-1 shows what this array looks like in memory. Figure 3-1. A sample array of integers To access an element in an array, you specify the corresponding index number in parentheses. Array indices are always zero-based. That means that MyArray(0) accesses the first cell in a one-dimensional array, MyArray(1) accesses the second cell, and so on. ' Access the value in row 0 (first row), column 1 (second column). One nice feature that VB .NET offers is array redimensioning. In VB .NET, all arrays start with an initial size, and any array can be resized. To resize an array, you use the ReDim keyword. Dim MyArray(10, 10) As Integer In this example, all the contents in the array will be erased when it’s resized. To preserve the contents, you can use the optional Preserve keyword when redimensioning the array. However, if you’re using a multidimensional array you’ll only be able to change the last dimension, or a runtime error will occur. Dim MyArray(10, 10) As Integer
Enumerations An enumeration is a group of related constants, each of which is given a descriptive name. Every enumerated value corresponds to a preset integer. In your code, however, you can refer to an enumerated value by name, which makes your code clearer and helps to prevent errors. For example, it’s much more straightforward to set the border of a label to the enumerated value BoderStyle.Dashed rather than the obscure numeric constant 3. In this case, Dashed is a value in the BorderStyle enumeration, and it represents the number 3. Here’s an example of an enumeration that defines different types of users: ' Define an enumeration called UserType with three possible values. Now you can use the UserType enumeration as a special data type that is restricted to one of three possible values. You assign or compare the enumerated value using the dot notation shown in the following example. ' Create a new value and set it equal to the UserType.Admin constant. Internally, enumerations are maintained as numbers. In the preceding example, 0 is automatically assigned to Admin, 1 to Guest, and 2 to Invalid. You can set a number directly into an enumeration variable, although this can lead to an undetected error if you use a number that doesn’t correspond to one of the defined values. In some scenarios, you might want to control what numbers are used for various values in an enumeration. This technique is typically used when the number has some specific meaning or corresponds to some other piece of information. For example, the following code defines an enumeration that represents the error code returned by a legacy component. Enum ErrorCode Now you can use the ErrorCode enumeration, which was defined earlier, with a function that returns an integer representing an error condition, as shown here: Dim Err As ErrorCode
You can use all the standard type of variable operations in VB .NET. When working with numbers, you can use various math symbols, as listed in Table 3-2. Visual Basic .NET follows the conventional order of operations, performing exponentiation first, followed by multiplication and division, and then addition and subtraction. You can also control order by grouping subexpressions with parentheses. Dim Number As Integer Table 3-2. Arithmetic Operations
When dealing with strings, you can use the concatenation operator (&), which joins together two strings. ' Join two strings together. Could also use the + operator. The addition operator (+) can also be used to join strings, but it’s generally clearer to use the concatenation operator. The concatenation operator automatically attempts to convert both variables in the expression to the string data type, if they are not already strings. In addition, Visual Basic .NET now provides special shorthand assignment operators. A few examples are shown here: ' Add 10 to MyValue (the same as MyValue = MyValue + 10). ............................................................................................................................ Line Termination Sometimes, code statements are too long to efficiently fit on a single line. In Visual Basic, you can break a code statement over multiple lines by adding a space followed by the line-continuation character (an underscore) to the end of the line. Here’s an example: ' A long line of code. ............................................................................................................................. Advanced Math In the past, every language has had its own set of keywords for common math operations such as rounding and trigonometry. In .NET languages, many of these keywords remain. However, you can also use a centralized Math class that’s part of the .NET Framework. This has the pleasant side effect of ensuring that the code you use to perform mathematical operations can easily be translated into equivalent statements in any .NET language with minimal fuss. To use the math operations, you invoke the methods of the System.Math class. These methods are shared, which means that they are always available and ready to use. (The next chapter explores the difference between shared and instance members in more detail.) The following code snippet shows some sample calculations that you can perform with the Math class. Dim MyValue As Integer The features of the Math class are too numerous to list here in their entirety. The preceding examples show some common numeric operations. For more information about the trigonometric and logarithmic functions that are available, refer to the MSDN reference for the Math class. Type ConversionsConverting information from one data type to another is a fairly common programming task. For example, you might retrieve text input for a user that contains the number you want to use for a calculation. Or, you might need take a calculated value and transform it into text you can display in a web page. The Visual Basic .NET rules for type conversion are slightly less strict than some other languages, like C#. For example, VB .NET will automatically allow the conversions shown here: Dim BigValue As Integer = 100 The problem with code like this, is that it isn’t guaranteed to work. Conversions are of two types: narrowing and widening. Widening conversions always succeed. For example, you can always convert a number into a string, or a 16-bit integer into a 32-bit integer. On the other hand, narrowing conversions may or may not succeed, depending on the data. If you’re converting a 32-bit integer to a 16-bit integer (as in the previous code snippet), you’ll encounter an error if the 32-bit number is larger than the maximum value that can be stored in a 16-bit data type. Similarly, some strings can’t be converted to numbers. A failed narrowing conversion will lead to an unexpected runtime error. It’s possible to tighten up Visual Basic’s type conversion habits by adding an Option Strict instruction to the beginning of your code files. Option Strict On In this case, VB .NET will not allow automatic or implicit data type conversions if they could cause an error or lose data. Instead, you’ll need to explicitly indicate that you want to perform a conversion. To perform an explicit data type conversion in VB .NET, you use the CType() function. This function takes two arguments. The first specifies the variable you want to convert, and the second specifies the data type you’re converting it to. Here’s how you would rewrite the earlier example with explicit conversions: Dim BigValue As Integer = 100 Just like implicit conversions, explicit conversions can still fail and produce a runtime error. The difference is that when you add the CType() function, you clearly indicate that you’re aware that a conversion is taking place. At the same time that you use CType(), you should add code that either validates your data before you attempt to convert it, or catches any errors using the error-handling techniques described in Chapter 11. You can also use the classic Visual Basic keywords such as Val(), CStr(), CInt(), CBool(), and so on to perform data type conversions with the standard data types. However, the CType() function is a nice generic solution that works for all scenarios. The examples in this book almost always use explicit conversion with the CType() function. A few exceptions apply. For example, Visual Basic’s built-in Val() function is more convenient than CType() in some scenarios because it just returns a zero if it fails to convert a string to a number. Dim TextString As String = "Hello" You’ll also find that you can use object methods to perform some conversions a little more elegantly. The next section demonstrates this approach. Object-Based Manipulation.NET is object-oriented to the core. In fact, even ordinary variables are really full-fledged objects in disguise. That means that common data types have the built-in smarts to handle basic operations (like counting the number of letters in a string). Even better, it means that you can manipulate strings, dates, and numbers in exactly the same way in C# and in VB .NET. This wouldn’t be true if developers used special keywords that were built into the C# or VB .NET language. As an example, every type in the .NET class library includes a ToString() method. The default implementation of this method returns the class name. In simple variables, a more useful result is returned: the string representation of the given variable. The following code snippet demonstrates the use of the ToString() method with an integer. Dim MyString As String To understand this example, you need to remember that all integers are based on the Int32 class in the .NET class library. The ToString() method is built in to the Int32 class, so it’s available when you use an integer in any language. You should also notice that the line of code that uses the ToString() method is virtually identical in both languages. The next few sections explore the object-oriented underpinnings of the .NET data types in more detail.
One of the best examples of how class members can replace built-in functions is found with strings. You might be familiar with the standard Visual Basic string functions such as Len(), Left(), Right(), and Instr(). These functions have been a part of Visual Basic and VBScript for years, and they’re still available in VB .NET. However, a better solution is to use the methods of the String class, which provides greater consistency between .NET languages. The following code snippet shows several ways to manipulate a string using its object nature. Dim MyString As String = "This is a test string " The first few statements use built-in methods, like Trim(), Substring(), ToUpper(), and Replace(). These methods generate new strings, and each of these statements replaces the current MyString with the new string object. The final statement uses a built-in Length property, which returns an integer that represents the number of letters in the string.
Note that the Substring() method requires a starting offset and a character length. Strings use zero-based counting. That means that the first letter is in position 0, the second letter is in position 1, and so on. This marks a sharp change from the traditional Visual Basic functions, which used one-based counting. This change is found throughout the .NET Framework for the sake of consistency. You can even use these methods in succession in a single (rather ugly) line: MyString = MyString.Trim.SubString(0, 4).ToUpper().Replace("IS", "AT") Or, to make life more interesting, you can use the string methods on string literals just as easily as string variables: MyString = "hello".ToUpper() ' Sets MyString to "HELLO" Table 3-3 lists some useful members of the System.String class. Table 3-3. Useful String Members
Table 3-3. Useful String Members (Continued)
The DateTime and TimeSpan Classes The DateTime and TimeSpan data types also have built-in methods and properties. These class members allow you to perform the following three useful tasks:
For example, the following block of code creates a DateTime object, sets it to the current date and time, and adds a number of days. It then creates a string that indicates the year that the new date falls in (“for example, “2003”). Dim MyDate As DateTime = DateTime.Now The next example shows how you can use a TimeSpan object to find the total number of minutes between two DateTime objects. Dim MyDate1 As DateTime = DateTime.Now These examples give you an idea of the flexibility .NET provides for manipulating date and time data. Tables 3-4 and 3-5 list some of the more useful built-in features of the DateTime and TimeSpan objects. Table 3-4. Useful DateTime Members
Table 3-5. Useful TimeSpan Members
Arrays also behave like objects in the new world of .NET. For example, if you want to find out the size of an array, you won’t use the old-fashioned UBound() function that’s built into the Visual Basic language. Instead, you can use the Array.GetUpperBound() method in any language. The following code snippet shows this technique in action. Dim MyArray() As Integer = {1, 2, 3, 4, 5} Dim Bound As Integer Arrays also provide a few other useful methods, which allow you to sort them, reverse them, and search them for a specified element. Table 3-6 lists some useful members of the System.Array class. Table 3-6. Useful Array Members Member Description Length Returns an integer that represents the total number of elements in all dimensions of an array. For example, a 3 × 3 array has a length of 9. GetLowerBound() and GetUpperBound() Determines the dimensions of an array. As with just about everything in .NET, you start counting at zero (which represents the first dimension). Clear() Empties an array’s contents. IndexOf() and LastIndexOf() Searches a one-dimensional array for a specified value and returns the index number. You cannot use this with multidimensional arrays. Sort() Sorts a one-dimensional array made up of comparable data such as strings or numbers. Reverse() Reverses a one-dimensional array so that its elements are backward, from last to first. Conditional StructuresIn many ways, conditional logic—deciding which action to take based on user input, external conditions, or other information—is the heart of programming. All conditional logic starts with a condition: a simple expression that can be evaluated to True or False. Your code can then make a decision to execute different logic depending on the outcome of the condition. To build a condition, you can use any combination of literal values or variables, along with logical operators. Table 3-7 lists the basic logical operators. Table 3-7. Logical Operators
You can use the comparison operators (<, >, <=, >=) with numeric types and strings. A string is deemed to be “less than” another string if it occurs earlier in an alphabetic sort. Thus “apple” is less than “attach.” The If … End If BlockThe If … End If block is the powerhouse of conditional logic, able to evaluate any combination of conditions and deal with multiple and different pieces of data. Here’s an example with an If … End If block that features two conditions: If MyNumber > 10 Then Keep in mind that the If … End If block matches one condition at most. For example, if MyNumber is greater than 10, the first condition will be met. That means the code in the first conditional block will run, and no other conditions will be evaluated. Whether or not MyString contains the text “hello” becomes irrelevant, because that condition will not be evaluated. The Select Case BlockVB .NET also provides a Select Case structure that you can use to evaluate a single variable or expression for multiple possible values. In the following code, each case examines the MyNumber variable, and tests if it’s equal to a specific integer. Select Case MyNumber If desired, you can handle multiple cases with one segment of code by including a list of comma-separated values in the Case statement. Select Case MyNumber Unlike the If … End If block, Select Case is limited to evaluating a single piece of information at a time. However, it provides a leaner, clearer syntax than the If … End If block for situations in which you need to test a single variable. Loop StructuresLoop structures allow you to repeat a segment of code multiple times. There are three basic types of loops in Visual Basic .NET. You choose the type of loop based on the type of task you need to perform. Your choices are as follows:
The For … Next block is a basic ingredient in many programs. It allows you to repeat a block of code a set number of times, using a built-in counter. To create a For … Next loop, you need to specify a starting value, an ending value, and the amount to increment with each pass. Here’s one example: Dim i As Integer In this example, the counter you’re using is a variable named i. The loop begins at 1 and ends at 10. The “Step 1” clause specifies that i will be increased by 1 each time the code passes through the loop. You can omit this part of the code, because 1 is the default increment. Once i reaches 10 the final pass is made through the loop. If you run this code using a tool like Visual Studio .NET, it will write the following numbers in the Debug window: 1 2 3 4 5 6 7 8 9 10 It often makes sense to set the counter variable based on the number of items you’re processing. For example, you can use a For … Next loop to step through the elements in an array by checking the size of the array before you begin. Here’s the code you would use: Dim StringArray() As String = {"one", "two", "three"} This code produces the following output: one two three ............................................................................................................................... Scope Changes from Visual Basic 6 In traditional Visual Basic, there were only two types of scope for a variable: form level and procedure level. VB .NET tightens these rules a notch by introducing block scope. Block scope means that any variables created inside a block structure (such as a conditional If… End If or a For… Next or a Do… Loop) are only accessible inside that block of code. For i = 0 To 10 This change won’t affect many programs. It’s really designed to catch a few more accidental errors. If you need to access a variable inside and outside of some type of block structure, just define the variable before the block starts. ............................................................................................................................. The For Each BlockVB .NET also provides a For Each block that allows you to loop through the items in a set of data. With a For Each block, you don’t need to create an explicit counter variable. Instead, you create a variable that represents the type of data you’re looking for. Your code will then loop until you’ve had a chance to process each piece of data in the set. For Each is particularly useful for traversing the data in collections and arrays. For example, the next code segment loops through the items in an array using For Each. This code is identical to the previous example, but a little simpler. Dim StringArray() As String = {"one", "two", "three"} In this case, the For Each loop is looking for string in the array. Thus, if defines a string variable named Element. If you used code like this, you wouldn’t retrieve any information at all: Dim StringArray() As String = {"one", "two", "three"} For Each iteration has one key limitation: It’s read-only. For example, if you wanted to loop through an array and change the values in that array at the same time, For Each code wouldn’t work. Instead, you would need to fall back on a For … Next block with a counter. The Do … Loop BlockFinally, Visual Basic supports a Do … Loop structure that tests a specific condition after each pass through the loop. To build your condition, you use the While or Until keyword. These two keywords are opposites. While means “as long as this is true,” and Until means “as long as this is not true.” Here’s an example that loops ten times. After each pass, the code evaluates whether the counter (i) has exceeded a set value. Dim i As Integer = 1 You can also place the condition at the beginning of the loop. In this case, the condition is tested before the loop is started. The following code is equivalent to the previous example, unless the condition you’re testing is False to begin with. In that case, none of the code in the loop will execute. Dim i As Integer = 1 On the other hand, if you place the condition at the end of the loop, the code will always be executed at least once.
Functions and subroutines are the most basic building block you can use to organize your code. Ideally, each function or subroutine will perform a distinct, logical task. By breaking your code down into procedures, you not only simplify your life, but you also make it easier to organize your code into classes and step into the world of object-oriented programming. Visual Basic distinguishes between two types of procedures: ordinary subroutines and functions. The only difference between the two is that functions return a value. To set the return value of a function, you can assign a value to the function name, just as in previous versions of Visual Basic. VB .NET also introduces the useful Return keyword, which allows you to exit a function and return a result in one quick, clear step. Subroutines are declared with the Sub keyword, and functions are declared with the Function keyword. Here is an example of each one: Private Sub MySub() You’ll notice that both of these procedures are preceded with the accessibility keyword Private. This indicates that these procedures won’t be accessible to code in a different class or module. The next chapter considers classes and accessibility in more detail. Calling your procedures is straightforward—you simply enter the name of procedure, followed by parentheses. If you call a function, you have the option of using the data it returns, or just ignoring it. ' This call is allowed. Procedures can also accept information through parameters. Parameters are declared in a similar way to variables. By convention, parameter names always begin with a lowercase first letter in any language. Here’s how you might create a function that accepts two parameters and returns their sum. Private Function AddNumbers(number1 As Integer, number2 As Integer) As Integer When calling a procedure, you specify any required parameters in parentheses, or use an empty set of parentheses if no parameters are required. ' Call a subroutine with no parameters. MySub() VB .NET supports overloading, which allows you to create more than one function or subroutine with the same name, but with a different set of parameters. When you call the procedure, the CLR automatically chooses the correct version by examining the parameters you supply. This is old hat to C programmers, but a valuable new introduction to the Visual Basic world. It allows you to collect different versions of several functions together. For example, you might allow a database search that returns an author name. Rather than create three functions with different names depending on the criteria, such as GetNameFromID(), GetNameFromSSN(), GetNameFromBookTitle(), you could create three versions of the GetCustomerName() function. Each function would have the same name, but a different signature, meaning it would require different parameters. To overload a procedure, you use the Overloads keyword. Here’s an example that provides two overloaded versions for the GetProductPrice() method. Private Overloads Function GetProductPrice(ID As Integer) As Decimal You can look up product prices based on the unique product ID, or the full product name, depending on whether you supply an integer or string argument: Dim Price As Decimal You cannot overload a function with versions that have the same signature—that is, the same number of parameters and parameter data types—because the CLR will not be able to distinguish them from each other. When you call an overloaded function, the version that matches the parameter list you supply is used. If no version matches, an error occurs.
Delegates Delegates are a new feature of the .NET languages. They allow you to create a variable that “points” to a procedure. You can use this variable at any time to invoke the procedure. Delegates help you write flexible code that can be reused in many different situations. The first step when using a delegate is to define its signature. A delegate variable can only point to a function or procedure that matches its specific signature (list of parameters). For example, if you have a subroutine that accepts a single string parameter, and another subroutine that accepts two string parameters, you’ll need to use a separate delegate type for each subroutine. This enforces a level of type safety that isn’t found with traditional function pointers in languages like C++. Here’s the code you use to define a delegate and its signature: ' Define a delegate that can represent any function that accepts a single Once you’ve defined a type of delegate, you can create and assign a delegate variable. For example, assume your program has the following function: Private Function TranslateEnglishToFrench(english As String) As String This function requires one string parameter and returns a string. Thus, it matches the signature used in the definition of the StringFunction delegate. That means you can create a StringFunction delegate variable, and use it to store a reference to the TranslateEnglishToFrench() function. To actually store the reference to the TranslateEnglishToFrench() function, you use the AddressOf statement. The following code demonstrates this technique: ' Create a delegate variable. Once you have a delegate variable that references a function, you can invoke the function through the delegate. To do this, you just use the delegate name as though it were the function name: Dim FrenchString As String In the previous code example, the procedure that the FunctionReference delegate points to will be invoked with the parameter "Hello" and the return value will be stored in the FrenchString variable. .......................................................................................................................... Delegates Are the Basis of Events Wouldn’t it be nice to have a delegate that could refer to more than one function at once, and invoke them simultaneously? That would allow the client application to have multiple “listeners,” and notify the listeners all at once when something happens. In fact, delegates do have this functionality, but you’re more likely to see it in use with .NET events. Events, which are described in the next chapter, are based on delegates, but work at a slightly higher level. In a typical ASP.NET program, you’ll use events extensively, but you’ll probably never work directly with delegates. ................................................................................................................................ The Last WordIt’s impossible to do justice to an entire language in a single chapter. However, if you’ve programmed before, you’ll find that this chapter provides all the information you need to get started with the .NET languages. As you work through the full ASP.NET examples in the following chapters, you can refer to this chapter to clear up any language issues. In the next chapter, you’ll learn about more important language concepts, and the object-oriented nature of .NET. blog comments powered by Disqus |