Working with Objects


In the .NET environment, and within Visual Basic in particular, you use objects all the time without even thinking about it. Every control on a form - in fact, every form - is an object. When you open a file or interact with a database, you are using objects to do that work.

Object Declaration and Instantiation

Objects are created using the New keyword, indicating that you want a new instance of a particular class. There are numerous variations on how or where you can use the New keyword in your code. Each one provides different advantages in terms of code readability or flexibility.

The most obvious way to create an object is to declare an object variable and then create an instance of the object:

  Dim obj As TheClass obj = New TheClass() 

The result of this code is that you have a new instance of TheClass ready for use. To interact with this new object, you use the obj variable that you declared. The obj variable contains a reference to the object, a concept explored later.

You can shorten the preceding code by combining the declaration of the variable with the creation of the instance, as illustrated here:

  Dim obj As New TheClass() 

Tip 

In previous versions of Visual Basic, this substitution was a bad idea because it had negative performance and maintainability effects. However, in Visual Basic 2005, there is no difference between the first example and this one, other than that the latter code is shorter.

The preceding code both declares the variable obj as datatype TheClass and creates an instance of the class, immediately creating an object that you can use. Another variation on this theme is as follows:

  Dim obj As TheClass = New TheClass() 

Again, this both declares a variable of datatype TheClass and creates an instance of the class. It is up to you how you create these instances, as it really a matter of style.

This third syntax example provides a great deal of flexibility while remaining compact. Though it is a single line of code, it separates the declaration of the variable’s datatype from the creation of the object.

Such flexibility is very useful when working with inheritance or multiple interfaces. You might declare the variable to be of one type - say, an interface - and instantiate the object based on a class that implements that interface. You’ll revisit this syntax when interfaces are covered in detail in Chapter 4.

So far you’ve been declaring a variable for new objects, but sometimes you may simply need to pass an object as a parameter to a method, in which case you can create an instance of the object right in the call to that method:

  DoSomething(New TheClass()) 

This calls the DoSomething method, passing a new instance of TheClass as a parameter. This can be even more complex. Perhaps, instead of needing an object reference, your method needs an Integer. You can provide that Integer value from a method on the object:

  Public Class TheClass   Public Function GetValue() As Integer     Return 42   End Function End Class 

You can then instantiate the object and call the method all in one shot, thus passing the value returned from the method as a parameter:

  DoSomething(New TheClass().GetValue()) 

Obviously, you need to carefully weigh the readability of such code against its compactness. At some point, having more compact code can detract from readability, rather than enhance it.

Object References

Typically, when you work with an object, you are using a reference to that object. Conversely, when you are working with simple datatypes, such as Integer, you are working with the actual value, rather than a reference. Let’s explore these concepts and see how they work and interact.

When you create a new object using the New keyword, you store a reference to that object in a variable, as shown here:

  Dim obj As New TheClass() 

This code creates a new instance of TheClass. You gain access to this new object via the obj variable. This variable holds a reference to the object. You might then do something like this:

  Dim another As TheClass another = obj 

Now, you have a second variable, another, which also has a reference to the same object. You can use either variable interchangeably, as they both reference the exact same object. Remember that the variable you have is not the object itself but just a reference or pointer to the object.

Dereferencing Objects

When you are done working with an object, you can indicate that you’re through with it by dereferencing the object. To dereference an object, simply set the object reference to Nothing:

 Dim obj As TheClass obj = New TheClass() obj = Nothing 

Once any or all variables that reference an object are set to Nothing, the .NET runtime can tell that you no longer need that object. At some point, the runtime will destroy the object and reclaim the memory and resources consumed by the object. You can find more information on the garbage collector in Chapter 5.

Between the time that you dereference the object and the time that the .NET Framework gets around to actually destroying it, the object simply sits in the memory, unaware that it has been dereferenced. Right before .NET destroys the object, the Framework calls the Finalize method on the object (if it has one). The Finalize method is discussed in Chapter 4.

Early Binding versus Late Binding

One of the strengths of Visual Basic has long been that it provides access to both early and late binding when interacting with objects.

Early binding means that code directly interacts with an object by directly calling its methods. Because the Visual Basic compiler knows the object’s datatype ahead of time, it can directly compile code to invoke the methods on the object. Early binding also enables the IDE to use IntelliSense to aid development efforts by enabling the compiler to ensure that you are referencing methods that exist and are providing the proper parameter values.

Late binding means that your code interacts with an object dynamically at runtime. This provides a great deal of flexibility because the code doesn’t care what type of object it is interacting with as long as the object supports the methods you want to call. Because the type of the object isn’t known by the IDE or compiler, neither IntelliSense nor compile-time syntax checking is possible, but in exchange you get unprecedented flexibility.

If you enable strict type checking by using Option Strict On in the project properties dialog or at the top of the code modules, then the IDE and compiler enforce early binding behavior. By default, Option Strict is turned off, so you have easy access to the use of late binding within the code. Chapter 2 discusses Option Strict. You can change this default directly in Visual Studio 2005 by selecting Tools image from book Options from the VS menu. You are then presented with the Options dialog, shown in Figure 3-1. Expanding the Projects and Solutions node reveals the VB defaults. Feel free to change any of these default settings.

image from book
Figure 3-1

Implementing Late Binding

Late binding occurs when the compiler can’t determine the type of object that you’ll be calling. This level of ambiguity is achieved through the use of the Object datatype. A variable of datatype Object can hold virtually any value, including a reference to any type of object. Thus, code such as the following could be run against any object that implements a DoSomething method that accepts no parameters:

  Option Strict Off Module LateBind   Public Sub DoWork(ByVal obj As Object)    obj.DoSomething()   End Sub End Module 

If the object passed into this routine does not have a DoSomething method that accepts no parameters, then an exception will be thrown. Thus, it is recommended that any code that uses late binding always provide exception handling:

 Option Strict Off Module LateBind   Public Sub DoWork(ByVal obj As Object)      Try        obj.DoSomething()     Catch ex As MissingMemberException       ' do something appropriate given failure       ' to call this method     End Try   End Sub End Module

Here, the call to the DoSomething method has been put in a Try block. If it works, then the code in the Catch block is ignored; but in the case of a failure, the code in the Catch block is run. You need to write code in the Catch block to handle the case in which the object does not support the DoSomething method call. This Catch block only catches the MissingMemberException, which indicates that the method doesn’t exist on the object.

While late binding is flexible, it can be error prone and is slower than early-bound code. To make a late-bound method call, the .NET runtime must dynamically determine whether the target object actually has a method that matches the one you’re calling. It must then invoke that method on your behalf. This takes more time and effort than an early-bound call whereby the compiler knows ahead of time that the method exists and can compile the code to make the call directly. With a late-bound call, the compiler has to generate code to make the call dynamically at runtime.

Using the CType Function

Whether you are using late binding or not, it can be useful to pass object references around using the Object datatype, converting them to an appropriate type when you need to interact with them. This is particularly useful when working with objects that use inheritance or implement multiple interfaces, concepts discussed in Chapter 4.

If Option Strict is turned off, which is the default, then you can write code using a variable of type Object to make an early-bound method call:

 Module LateBind   Public Sub DoWork(obj As Object)         Dim local As TheClass      local = obj      local.DoSomething()   End Sub End Module

This code uses a strongly typed variable, local, to reference what was a generic object value. Behind the scenes, Visual Basic converts the generic type to a specific type so that it can be assigned to the strongly typed variable. If the conversion can’t be done, you get a trappable runtime error.

The same thing can be done using the CType function. If Option Strict is enabled, then the previous approach won’t compile, and the CType function must be used. Here is the same code making use of CType:

 Module LateBind   Public Sub DoWork(obj As Object)      Dim local As TheClass      local = CType(obj, TheClass)      local.DoSomething()   End Sub End Module

This code declares a variable of type TheClass, which is an early-bound datatype that you want to use. The parameter you’re accepting, though, is of the generic Object datatype, so you use the CType() method to gain an early-bound reference to the object. If the object isn’t of type TheClass, then the call to CType() fails with a trappable error.

Once you have a reference to the object, you can call methods by using the early bound variable, local. This code can be shortened to avoid the use of the intermediate variable. Instead, you can simply call methods directly from the datatype:

 Module LateBind   Public Sub DoWork(obj As Object)      CType(obj, TheClass).DoSomething()   End Sub End Module

Even though the variable you’re working with is of type Object and therefore any calls to it will be late bound, you use the CType method to temporarily convert the variable into a specific type - in this case, the type TheClass.

Tip 

If the object passed as a parameter is not of type TheClass, you get a trappable error, so it is always wise to wrap this code in a Try...Catch block.

As Chapter 4 discusses, the CType function can also be very useful when working with objects that implement multiple interfaces. When an object has multiple interfaces, you can reference a single object variable through the appropriate interface as needed.

Using the DirectCast Function

Another function that is very similar to CType is DirectCast. DirectCast also converts values of one type into another type. It works in a more restrictive fashion than CType, but the trade-off is that it can be somewhat faster than CType:

  Dim obj As TheClass obj = New TheClass DirectCast(obj, ITheInterface).DoSomething() 

This is similar to the last example with CType, illustrating the parity between the two functions. There are differences, however. First, DirectCast works only with reference types, whereas CType accepts both reference and value types. For instance, CType can be used in the following code:

  Dim int As Integer = CType(123.45, Integer) 

Trying to do the same thing with DirectCast would result in a compiler error, as the value 123.45 is a value type, not a reference type.

Second, DirectCast is not as aggressive about converting types as CType. CType can be viewed as an intelligent combination of all the other conversion functions (such as CInt, CStr, and so on). DirectCast, on the other hand, assumes that the source data is directly convertible, and it won’t take extra steps to convert the data.

As an example, consider the following code:

  Dim obj As Object = 123.45 Dim int As Integer = DirectCast(obj, Integer) 

If you were using CType this would work, as CType uses CInt-like behavior to convert the value to an Integer. DirectCast, however, will throw an exception because the value is not a directly convertible o Integer.

Using the TryCast Function

A function similar to DirectCast is TryCast. TryCast converts values of one type into another type, but unlike DirectCast, if it can’t do the conversion, then TryCast doesn’t throw an exception. Instead, TryCast simply returns Nothing if the cast can’t be performed. TryCast only works with reference values; it cannot be used with value types such as Integer or Boolean.

Using TryCast, you can write code like this:

  Module LateBind   Public Sub DoWork(obj As Object)      Dim temp As TheClass = TryCast(obj)      If temp Is Nothing Then        ' the cast couldn't be accomplished        ' so do no work      Else        temp.DoSomething()      End If   End Sub End Module 

If you aren’t sure whether a type conversion is possible, it is often best to use TryCast. This function avoids the overhead and complexity of catching possible exceptions from CType or DirectCast and still provides you with an easy way to convert an object to another type.




Professional VB 2005 with. NET 3. 0
Professional VB 2005 with .NET 3.0 (Programmer to Programmer)
ISBN: 0470124709
EAN: 2147483647
Year: 2004
Pages: 267

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