Chapter 3: Major VB .NET Changes
VB .NET introduces major changes to the VB language. Some are modifications to existing ways of working, whereas others are brand new. This chapter will cover some of those changes, but this is by no means an exhaustive list of all changes from VB to VB .NET. First, you'll see some of the features that have changed. Then you will see some of the new features.
There are a number of general changes to be aware of when moving from VB to VB .NET. Among them are topics such as the removal of default properties, subs and functions requiring parentheses, and ByVal being the default method for passing parameters. These changes, and others, are detailed in this section.
In VB6, objects could have default properties. For example, the following code is perfectly valid in VB6, if you assume that Text1 is a text box:
This code takes the string "Hello, World" and sets the default property of the text box, the Text property, to the string. The major drawback to default properties is that they require you to have a Set command in VB. For example, take a look at the following block of VB6 code:
Dim txtBillTo as TextBox Dim txtShipTo as TextBox txtShipTo = txtBillTo
The line of code txtShipTo = txtBillTo sets the Text property of txtShipTo to the value in the Text property of txtBillTo. But what if that isn't what you wanted? What if, instead, you wanted to create an object reference in txtShipTo that referred to the object txtBillTo? You'd have to use this code:
Set txtShipTo = txtBillTo
As you can see, default properties require you to use the Set keyword to set references from one object variable to another.
VB .NET gets around this problem by getting rid of default properties. Therefore, to copy the Text property from txtBillTo into the Text property of txtShipTo, you have to use this code:
txtShipTo.Text = txtBillTo.Text
Setting the two variables equal to each other sets a reference from one to the other. In other words, you can set an object reference without the Set keyword:
txtShipTo = txtBillTo ` Object reference in VB.NET
Default Properties Require Parameterized Properties
To be more precise, default properties without parameters are no longer supported. Default properties that require parameters are still valid. Default properties with parameters are most common with collection classes, such as in ADO. In an ADO example, if you assume that rs is an ADO Recordset, check out the following code:
rs.Fields.Item(x).Value ` OK, fully qualified rs.Fields(x).Value ` OK, because Item is parameterized rs.Fields(x) ` Error, because Fields is not parameterized
The easy solution is to fully qualify everything. This avoids any confusion about which properties are parameterized and which are not. However, as you know from your VB days, the number of dots you have should be minimized. The reason is that each dot requires an OLE lookup that slows you down. Therefore, you should code carefully when dealing with parameters.
Subs and Functions Require Parentheses
As you saw in the last chapter when you used the MsgBox function, you must now always use parentheses with functions, even if you are ignoring the return value. In addition, you must use parentheses when calling subs, which you did not do in VB6. For example, assume that you have this sub in both VB6 and VB .NET:
Sub foo(ByVal Greeting As String) ` implementation code here End Sub
In VB6, you could call this sub in one of two ways:
foo "Hello" Call foo("Hello")
In VB .NET, you also could call this sub in one of two ways:
Foo("Hello") Call foo("Hello")
The difference between the way VB and VB .NET handle this is, of course, that the parentheses are always required in the VB .NET calls, even though you aren't returning anything. In VB .NET, the Call statement is still supported, but it is not really necessary.
Changes to Boolean Operators
The And, Not, and Or operators were to have undergone some changes in VB .NET. Microsoft originally said that the operators would short-circuit, but now they are staying the way they worked in VB6. Short-circuiting means that if you are examining two conditions with the And operator and the first one is false, you shouldn't need to examine the second condition. Because there is no change in VB .NET, this means that, as in VB6, if you had two parts of an And statement and the first failed, you would still examine the second part. Examine the following code:
Dim x As Integer Dim y As Integer x = 1 y = 0 If x = 2 And y = 5/y Then ...
As a human, you know that the variable x is equal to 1. Therefore, when you look at the first part of the If statement, you know that x is not equal to 2, so you would logically think it should quit evaluating the expression. However, VB and VB .NET examine the second part of the expression, so this code would cause a divide-by-zero error, even though the error is in the second part of the expression, and the first part has already been found to be false.
If you want short-circuiting, VB .NET has introduced a couple of new operators: AndAlso and OrElse. In this case, the following code would not generate an error in VB .NET:
Dim x As Integer Dim y As Integer x = 1 y = 0 If x = 2 AndAlso y = 5/y Then ...
This code does not cause an error; instead, because x is not equal to 2, VB .NET does not even examine the second condition.
You can now initialize your variables when you declare them. You could not do this in VB6. In VB6, the only way to initialize a new variable was to do so on a separate line, like this:
Dim x As Integer x = 5
In VB .NET, you can rewrite this into one line of code:
Dim x As Integer = 5
Another significant and much-requested change is that of declaring multiple variables, and what data type they assume, on one line. For example, you might have the following line:
Dim x, y As Integer
As you're probably aware, in VB6, y would be an Integer data type, but x would be a Variant. In VB .NET, this has changed, so both x and y are Integers. If you think, "It's about time," there are many who agree. This should remove a number of bugs and strange type conversions experienced by new VB developers. It should also make the code more efficient by making variables the expected type instead of using the Object type (which replaces the Variant type, as you will see later).
Support for New Assignment Operators
VB .NET now supports shortcuts for performing certain assignment operations. In VB6, you incremented x by 1 with the following line of code:
x = x + 1
In VB .NET, you can type an equivalent statement like this:
x += 1
Not only can you use the plus sign, but VB .NET now also supports -=, *=, /=, \=, and ^= from a mathematical standpoint, and &= for string concatenation. If all this looks like C/C++, that's where it came from. However, the ++ operator is not supported. Microsoft developers made a decision not to include the ++ operator because they felt it made the code more difficult to read.
Because VB .NET is in beta, and has not yet been performance tuned, it is unclear as to whether these new assignment operators will be more efficient than their more verbose counterparts. These operators did tend to be more efficient in C/C++, due to a more efficient use of the CPU's registers. Therefore, it will be interesting to test these new operators when the final, tuned version of VB .NET is released.
ByVal Is Now the Default
In what many consider a strange decision, the default way to pass parameters in VB has always been by reference (ByRef). The decision was actually made because passing by reference is faster within the same application, but can be costly if you are calling components across process boundaries. If you're a little rusty, by reference means that you are passing only the memory address of a variable into the called routine. If the called routine modifies the variable, it actually just updates the value in that memory location, and therefore the variable in the calling routine also changes. Passing data by value (ByVal) means that you are actually sending a copy of the data to the called routine. The called routine must set aside a new area in memory to store that value. If the called routine changes the value, it is changed in the memory location set aside by the called routine, but the memory location of the calling routine is unaffected.
Take this VB6 example:
Private Sub Command1_Click() Dim x As Integer x = 3 foo x MsgBox x End Sub Sub foo(y As Integer) y = 5 End Sub
If you run this example in VB6, the message box shows the value 5. That happens because in VB6, when you pass x to foo, you are just sending the memory address of the variable x. So, when foo modifies y to 5, it changes the value in the same memory location to which x points, and this causes the value of x to change as well.
If you tried to type this example into VB .NET, you'd see something happen. First, of course, you'd have to add parentheses around x in your call to foo. However, when you tried to type the definition of foo, VB .NET would automatically add the word ByVal into the definition, so it would end up looking like this:
Sub foo(ByVal y As Integer)
If you wanted to pass by reference, you would have to add the ByRef keyword yourself, instead of VB .NET using the new default of ByVal. This should cut down on errors like those seen by novice users who didn't understand the concept of passing by reference in previous versions of VB. So, in VB .NET, accepting the defaults results in ByVal data passing. If you run this code in VB .NET, changing y to 5 does not affect the value of x at all. Running this code in VB .NET would cause you to see 3 in the message box.
Passing data ByVal is a benefit to those of you calling procedures across process boundaries, something that is common in the world of distributed applications. The reason it is a benefit is because of how you pass parameters across boundaries. If you have two routines in the same process, and one passes a parameter to the other ByRef, both routines can access the same memory location. However, if you now move one of those routines into another process, they cannot access the same memory (at least not easily). So, even if you pass a parameter to an out-of-process routine using ByRef, the called routine has to make a copy of the data and set up memory for it. Then any changes made in the called routine have to be marshaled back to the calling routine, which requires an expensive and slow round-trip across process boundaries.
By passing parameters to out-of-process routines using ByVal, you do not have to marshal any changes back to the calling routine. Many developers built out-of-process components in VB but were passing the parameters ByRef, not realizing that it was actually slower than passing them ByVal. VB .NET's default of passing parameters ByVal should take care of many of these issues.
VB .NET adds the ability to create variables that are visible only within a block. A block is any section of code that ends with one of the words End, Loop, or Next. This means that For...Next and If...End If blocks can have their own variables. Take a look at the following code:
While y < 5 Dim z As Integer ... End While
The variable z is now visible only within the While loop. It is important to realize that although z is visible only inside the While loop, its lifetime is that of the procedure. That means if you re-enter the While statement, z will have the same value that it did when you left. Therefore, it is said that the scope of z is block level, but its lifetime is procedure level.
While...Wend Becomes While...End While
The While loop is still supported, but the closing of the loop is now End While instead of Wend. If you type Wend, the editor automatically changes it to End While. This change finally moves the While loop into synch with most other VB block structures, which all end with an End <block> syntax.
VB .NET has changes that affect how you define and work with procedures. Some of those changes are mentioned in this section.
Optional Arguments Require a Default Value
In VB6, you could create an optional argument (or several optional arguments) when you defined a procedure. You could, optionally, give them a default value. That way, if someone chose not to pass in a value for an argument, you had a value in it. If you did not set a default value and the caller did not pass in a value, the only way you had to check was to call the IsMissing statement.
IsMissing is no longer supported because VB .NET will not let you create an optional argument that does not have a default value. IsMissing is not needed because an optional argument is guaranteed to have a value. For example, your declaration might look like this:
Sub foo(Optional ByVal y As Integer = 1)
Notice that the Optional keyword is shown, just as it was in VB6. This means a parameter does not have to be passed in. However, if it is not passed in, y is given the default value of 1. If the calling routine does pass in a value, of course, y is set to whatever is passed in.
Static Not Supported on Subs or Functions
In VB6, you could put Static in the declaration of a sub or function. Doing so made all variables in that sub or function static, which meant that they retained their values between calls to the procedure. For example, this was legal in VB6:
Static Sub foo() Dim x As Integer Dim y As Integer x = x + 1 y = y + 2 End Sub
In this example, x will retain its value between calls. So, the second time this procedure is called, x already has a value of 1, and the value of x will be incremented to 2. The variable y would have the value of 2, and therefore the second time in it would be incremented to 4.
VB .NET does not support the Static keyword in front of the sub or function declaration anymore, like VB6 did, as shown in the earlier example. In fact, if you want an entire sub or function to be static, you need to place Static in front of each variable declaration for which you want to preserve the value. This is the only way to preserve values in variables inside a sub or function. In VB .NET, the equivalent sub would look like this:
Sub foo() Static x As Integer Static y As Integer x = x + 1 y = y + 2 End Sub
The Return Statement
The Return statement can be used to produce an immediate return from a called procedure, and can optionally return a value. For example, look at this block of code:
Function foo() As Integer While True Dim x As Integer x += 1 If x >= 5 Then Return x End If End While End Function
In this code, you enter what normally would be an infinite loop by saying While True. Inside the loop, you declare an integer called x and begin incrementing it. You check the value of x and when it becomes greater than or equal to 5, you call the Return statement and return the value of x. This causes an immediate return, which means it does not wait to hit the End Function statement.
The old way of doing it still works, however. For example, to rewrite this procedure using the old approach to return a value, you would make it look like the following code. This sets the name of the procedure, foo, to the value to be returned. Then you have to exit the loop so that you'll hit End Function. You also could have used Exit Function instead of Exit Do.
Function foo() As Integer Do While True Dim x As Integer x += 1 If x >= 5 Then foo = x Exit Do End If Loop End Function
ParamArrays Are Now Passed ByVal
A parameter array, or ParamArray, is used when you do not know how many values you will pass into a procedure. A ParamArray allows for an unlimited number of arguments. A parameter array automatically sizes to hold the number of elements you are passing in.
A procedure can have only one ParamArray, and it must be the last argument in the definition. The array must be one-dimensional and each element must be the same data type. However, the default data type is Object, which is what replaces the Variant data type in VB .NET.
In VB6, all the elements of a ParamArray are always passed ByRef. This cannot be changed. In VB .NET, all the elements are passed ByVal. This cannot be changed. Again, ByRef was used in previous versions of VB because it was more efficient for passing parameters within a program all running in the same application space. When working with out-of-process components, however, it is more efficient to pass parameters ByVal, as explained in the earlier section entitled "ByVal Is Now the Default."
Properties Can Be Modified ByRef
In VB6, if a class had a property, you could pass that property to a procedure as an argument. If you passed the property ByVal, of course, it just copied the value. If you passed it ByRef, the called procedure might modify the value, but this new value was not reflected back in the object's property.
In VB .NET, however, you can pass a property to a procedure ByRef, and any changes to the property in the called procedure will be reflected in the value of the property for the object.
Take the following VB .NET example. Don't worry if the Class syntax looks strange; just realize that you are creating a class called Test with one property: Name. You instantiate the class in the Button1_Click event procedure, and pass the Name property, by reference, to foo. foo modifies the variable and ends. You then use a message box to print out the Name property.
Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Dim x As New Test() foo(x.Name) MsgBox(x.Name) End Sub Sub foo(ByRef firstName As String) firstName = "Torrey" End Sub Public Class Test Dim firstName As String Property Name() As String Get Name = firstName End Get Set(ByVal Value As String) firstName = Value End Set End Property End Class
When you run this example, the message box will display "Torrey". This shows that the property of the object is being passed by reference, and that changes to the variable are reflected back in the object's property. This is new in VB .NET.
Arrays have undergone some changes as well. Arrays could be somewhat confusing in previous versions of VB. VB .NET seeks to address any confusion by simplifying the rules and removing the capability to have nonzero lower boundaries.
In VB6, if you left the default for arrays to start at 0, declaring an array actually gave you the upper boundary of the array, not the number of elements. For example, examine the following code:
Dim y(2) As Integer y(0) = 1 y(1) = 2 y(2) = 3
In this VB6 code, you declare that y is an array of type Integer, and the upper boundary is 2. That means you actually have three elements: 0-2. You can verify this by setting those three elements in code.
In VB .NET, array declaration was going to change, so that the parameter was the number of elements. However, due to the possibility of breaking existing code in the upgrade process, this has been changed back to the way it worked in VB.
If you're wondering why this book points out something that didn't change in a chapter about changes, it is because Microsoft had announced that this would change, but then pulled back in the face of opposition from existing VB developers. Therefore, it is important to point out that it still works the same as it did before, except for the change of the lower boundary always being 0.
Lower Boundary Is Always Zero
VB6 allowed you to have a nonzero lower boundary in your arrays in a couple of ways. First, you could declare an array to have a certain range. If you wanted an array to start with 1, you declared it like this:
Dim y(1 To 3) As Integer
This would create an array with three elements, indexed 1-3. If you didn't like this method, you could use Option Base, which allowed you to set the default lower boundary to either 0 (the default) or 1.
VB .NET removes those two options from you. You cannot use the 1 to x syntax, and Option Base is no longer supported. In fact, because the lower boundary of the array is always 0, the Lbound function is not supported in VB .NET.
Array Assignment Is ByRef Instead of ByVal
In VB6, if you had two array variables and set one equal to the other, you actually were creating a copy of the array in a ByVal copy. Now, in VB .NET, setting one array variable to another is actually just setting a reference to the array. To copy an array, you can use the Copy method of the Array object.
Option Strict is a new statement that specifically disallows any automatic type conversions that would result in data loss. You can use only widening conversions; this means you could convert from an Integer to a Long, but you could not convert from a Long to an Integer. Option Strict also prevents conversions between numbers and strings.
Option Strict is off by default in Visual Studio .NET Beta 2. To turn it on, go to the top of the code window and type Option Strict On. Note that the default value for Option Strict has changed with almost every new build of Visual Studio .NET, and it is difficult to predict whether Option Strict will be on or off by default in the final product.
If you go to the top of a module and type Option Strict On, you can see that the IDE recognizes potential type conversion problems with the following lines of code:
Dim longNumber As Long Dim integerNumber As Integer integerNumber = longNumber
With this code, the IDE will underline longNumber and a tooltip will tell you the following: Option Strict disallows implicit conversions from Long to Integer.
For what it's worth, I strongly recommend that you use Option Strict On and Option Explicit On. In VS .NET Beta 2, Option Explicit is on by default, but again there is no guarantee this will be the case in the final product. Turning on both Option Explicit and Option Strict can help reduce errors that can occur only at runtime.
Data Type Changes
There are several changes to data types that are important to point out. These changes can have an impact on the performance and resource utilization of your code. The data types in VB .NET correspond to the data types in the System namespace, which is important for cross-language interoperability.
All Variables Are Objects
Technically, in VB .NET, all variables are subclassed from the Object base class. This means that you can treat all variables as objects. For example, to find the length of a string, you could use the following code:
Dim x As String x = "Hello, World" MsgBox(x.Length)
This means that you are treating x as an object, and examining its Length property. Other variables have other properties or methods. For example, an Integer has a ToString method that you can use, which you will see in a moment.
Short, Integer, and Long
In VB .NET, the Short data type is a 16-bit integer, the Integer is a 32-bit integer, and the Long is a 64-bit integer. In VB6 code, the Integer was a 16-bit integer and the Long was a 32-bit integer. It became common for VB developers to use the Long in place of the Integer, because the Long performed better on 32-bit operating systems than Integer, which was just 16-bit. However, on 32-bit operating systems, 32-bit integers perform better than 64-bit integers, so in VB .NET, you will most likely want to return to using the Integer data type instead of the Long data type.
Automatic String/Numeric Conversion Not Supported by Option Strict
In VB6, it was easy to convert from numbers to strings, and vice versa. For example, examine this block of code:
Dim x As Integer Dim y As String x = 5 y = x
In VB6, there is nothing wrong with this code. VB will take the value 5 and automatically convert it into the string "5". VB .NET, however, disallows this type of conversion if Option Strict is turned on. Instead, you would have to use the CStr function to convert a number to a string, or the Val function to convert a string to a number. You could rewrite the preceding code for VB .NET in this manner:
Dim x As Integer Dim y As String x = 5 y = CStr(x) y = x.ToString ` This is equivalent to the previous line
Fixed-Length Strings Not Supported
In VB6, you could declare a fixed-length string by using a declaration like the one shown here:
Dim y As String * 30
This declared y to be a fixed-length string that could hold 30 characters. If you try this same code in VB .NET, you will get an error. All strings in VB .NET are variable length.
All Strings Are Unicode
If you got tired of worrying about passing strings from VB to certain API calls that accepted either ANSI or Unicode strings, you will be happy to hear that all strings in VB .NET are Unicode.
The Value of True
Since Visual Basic 1.0, the value of True in VB and Access has been equal to -1. The .NET Framework declares that True should be equal to 1. This is an apparent disconnect between VB .NET and the underlying .NET Framework.
In reality, 0 is False and any nonzero is True in VB .NET. However, if you ask for the value of True, you will get -1 inside of VB .NET. You can verify that any nonzero is True by using this code:
Dim x As Integer x = 2 If CBool(x) = True Then MsgBox("Value is True") End If
If you make x any positive or negative integer, the CBool function will return True. If you set x equal to 0, CBool will return False. Even though True is actually shown as -1 in VB .NET, if you pass it out to any other .NET language, it is seen as 1. This means that all other .NET languages see it as the correct value.
Just as it had said it was changing how arrays were dimensioned, Microsoft originally said that the value of True in VB .NET was going to be 1. However, enough VB developers complained, and Microsoft decided to leave True as -1. This is a shame, but not because True should be 1. It is a shame because it means a number of developers have written code that looks for the value -1 instead of the constant True. The important thing to understand is this: Do not code for the value (1 or -1). Just use the keyword True and you will avoid any problems.
The Currency Data Type Has Been Replaced
The Currency data type has been replaced by the Decimal data type. The Decimal data type is a 12-byte signed integer that can have up to 28 digits to the right of the decimal place. It supports a much higher precision than the Currency data type, and has been designed for applications that cannot tolerate rounding errors. The Decimal data type has a direct equivalent in the .NET Framework, which is important for cross-language interoperability.
The Variant Data Type Has Been Replaced
The Variant data type has been replaced. Before you start thinking that there is no longer a catch-all variable type, understand that the Variant has been replaced by the Object data type. The Object data type takes up only four bytes because all it holds is a memory address. Therefore, even if you set the variable to an integer, the Object variable holds four bytes that point to the memory used to store the integer. The integer is stored on the heap. It will take up 8 bytes plus 4 bytes for the integer, so it consumes a total of 12 bytes. Examine the following code:
Dim x x = 5
In this case, x is a variable of type Object. When you set x equal to 5, VB .NET stores the value 5 in another memory location and x stores the address of that memory location. When you attempt to access x, a lookup is required to find that memory address and retrieve the value. Therefore, just like the Variant, the Object data type is slower than using explicit data types.
According to the VB .NET documentation, the Object data type allows you to play fast-and-loose with data type conversion. For example, look at the following code:
Dim x x = "5" ` x is a string x -= 2
In this example, x will now hold the numeric value 3. The only way you can run this example is if you set Option Strict Off in the file. If you change the code to use string concatenation, the conversion also works fine. For example, the following code will run without an error, and x will end up holding the string "52":
Dim x x = "5" ` x is a string x &= 2
An Object data type can be Nothing. In other words, it can hold nothing, which means it doesn't point to any memory address. You can check for Nothing by setting the Object variable equal to Nothing, by using the IsNothing function, or asking if an object Is Nothing. All three checks are shown in the following code:
Dim x If x = Nothing Then MsgBox("Nothing") If IsNothing(x) Then MsgBox("Still nothing") If x Is Nothing Then MsgBox("And Still Nothing")
Structured Error Handling
Error handling has changed in VB .NET. Actually, the old syntax still works, but there is a new error handling structure called Try...Catch...Finally that removes the need to use the old On Error Goto structure.
The overall structure of the Try...Catch...Finally syntax is to put the code that might cause an error in the Try portion, and then catch the error. Inside the Catch portion, you handle the error. The Finally portion runs code that happens after the Catch statements are done, regardless of whether or not there was an error. Here is a simple example:
Dim x, y As Integer ` Both will be integers Try x \= y ` cause division by zero Catch ex As Exception msgbox(ex.Message) End Try
The ex As Exception part of the Catch statement is optional.
Here, you have two variables that are both integers. You attempted to divide x by y, but because y has not been initialized, it defaults to 0. That division by zero raises an error, and you catch it in the next line. The variable ex is of type Exception, which holds the error that just occurred, so you simply print the Message property, much like you printed Err.Description in VB6.
In fact, you can still use Err.Description, and the Err object in general. The Err object will pick up any exceptions that are thrown. For example, assume that your logic dictates that an error must be raised if someone's account balance falls too low, and another error is raised if the balance drops into the negative category. Examine the following code:
Try If bal < 0 Then Throw New Exception("Balance is negative!") ElseIf bal > 0 And bal <= 10000 Then Throw New Exception("Balance is low; charge interest") End If Catch MessageBox.Show("Error: " & Err.Description) End Try
In this case, your business logic says that if the balance drops below zero, you raise an error informing the user that the balance is below zero. If the balance drops below 10,000 but remains above zero, you notify the user to start charging interest. In this case, Err.Description picks up the description you threw in your Exception.
You can also have multiple Catch statements to catch various errors. To have one Catch statement catch a particular error, you add a When clause to that Catch. Examine this code:
Dim x As Integer Dim y As Integer Try x \= y ` cause division by zero Catch ex As Exception When Err.Number = 11 MsgBox("You tried to divide by zero") Catch ex As Exception MsgBox("Acts as catch-all") End Try
In this example, you are looking for an Err.Number of 11, which is the error for division by zero. Therefore, if you get a division-by-zero error, you display a message box that says You tried to divide by zero. However, if a different error were to occur, you would drop into the Catch without a When clause. In effect, the Catch without a When clause acts as an "else" or "otherwise" section to handle anything that was not handled before.
Notice that the code does not fall through all the exceptions; it stops on the first one it finds. In the preceding example, you will raise an Err.Number of 11. You will see the message You tried to divide by zero, but you will skip over the catch-all Catch.
If you want to run some code at the end, regardless of which error occurred (or, indeed, if no error occurred), you could add a Finally statement. The code to do so follows:
Dim x As Integer Dim y As Integer Try x \= y ` cause division by zero Catch ex As Exception When Err.Number = 11 MsgBox("You tried to divide by zero") Catch ex As Exception MsgBox("Acts as catch-all") Finally MsgBox("Running finally code") End Try
In this code, whether or not you hit an error, the code in the Finally section will execute.
Exiting a Try...Catch...Finally Early
Sometimes you want to exit a Try...Catch...Finally early. To exit early, use the Exit Try statement. Exit Try can be placed in any Catch block or in the Try block, but not in the Finally block. Exit Try is supposed to break you out of the Try immediately, ignoring any Finally code. However, in Beta 2, Exit Try drops immediately to the Finally block. Expect this to be fixed in the final version of VS .NET. The syntax would look like this:
Dim x As Integer Dim y As Integer Try x \= y ` cause division by zero Catch ex As Exception When Err.Number = 11 msgbox("You tried to divide by zero") Exit Try Catch ex As Exception msgbox("Acts as catch-all") Finally msgbox("Running finally code") End Try
Structures Replace UDTs
User-defined types, or UDTs, were a way to create a custom data type in VB6. You could create a new data type that contained other elements within it. For example, you could create a Customer data type using this syntax:
Private Type Customer Name As String Income As Currency End Type
You could then use that UDT in your application, with code like this:
Dim buyer As Customer buyer.Name = "Martha" buyer.Income = 20000 MsgBox(buyer.Name & " " & buyer.Income)
The Type statement is no longer supported in VB .NET. It has been replaced by the Structure statement. The Structure statement has some major changes, but to re-create the UDT shown earlier, the syntax is this:
Structure Customer Dim Name As String Dim Income As Decimal End Structure
Notice that the only real difference so far is that you have to Dim each variable inside the structure, which is something you did not have to do in the Type statement, even with Option Explicit turned on. Notice also that Dim is the same as Public here, meaning that the variables are visible to any instance of the structure.
Structures have many other features, however. One of the biggest differences is that structures can support methods. For example, you could add a Shipping method to the Customer structure to calculate shipping costs based on delivery zone. This code adds a DeliveryZone property and a DeliveryCost function:
Structure Customer Dim Name As String Dim Income As Decimal Dim DeliveryZone As Integer Function DeliveryCost() As Decimal If DeliveryZone > 3 Then Return 25 Else Return CDec(12.5) End If End Function End Structure
Here, you have a built-in function called DeliveryCost. To use this structure, your client code would look something like this:
Dim buyer As Customer buyer.Name = "Martha" buyer.Income = 20000 buyer.DeliveryZone = 4 msgbox(buyer.DeliveryCost)
In this case, the message box would report a value of 25.
If you think this looks like a class, it certainly is similar. In fact, structures can have properties, methods, and events. They also support implementing interfaces and they can handle events. There are some caveats, however. Some of those stipulations include the following:
You cannot inherit from a structure.
You cannot initialize the fields inside a structure. For example, this code is illegal:
Structure Customer Dim Name As String = "Martha" End Structure
Properties are public by default, instead of private as they are in classes.
Structures are value types rather than reference types. That means if you assign a structure variable to another structure variable, you get a copy of the structure and not a reference to the original structure. The following code shows that a copy is occurring because an update to seller does not update buyer:
Dim buyer As Customer Dim seller ` Object data type seller = buyer seller.Name = "Linda" MsgBox(buyer.Name) MsgBox(seller.Name)
Note that the preceding code will not work if you have Option Strict turned on. If you want to test this, you'll have to enter Option Strict Off.