Programming with the Framework Class Library
Because the Framework Class Library contains classes in the true object-oriented spirit of that word, there are two primary ways you will find yourself using these base classes:
Black boxes that you can call into
Classes that you can inherit from and extend to craft your own functionality
Instantiating Objects from the Class Library
The use of base classes as a black box is probably the primary path for most developers. In this mode, your code will be treating the class library as a simple API to get at core functions on your particular operating system.
Using the class library classes in this manner does not represent a departure from the programming model that Visual Basic developers are used to. As an example, if you have programmed Visual Basic applications that have made use of the ADO library, you probably did the following:
You set a reference to the code library through the VB IDE.
You Dim'd a container for one of the ADO objects.
After you had a container object, you instantiated a version of an ADO object into it.
After that, you simply invoked its methods and properties as needed.
With Visual Basic .NET, your consumption of Framework classes will follow the exact same pattern.
Not all classes in the Framework class library allow you to create instances just by using the New operatorsome force you to go through a class factory method to get your initial instance of the class. The WebRequest class is one example: In order to create a new WebRequest object, you have to use the WebRequest.Create method. You should also be aware that some classes have static methods and properties. Static methods apply to classes and not instances. That means that you don't have to create an instance of the class in order to use the method. The WebRequest.Create method is an example of a static method: We simply call it using the class reference without an actual instance having been created.
Inheriting from the Framework Class Library
With the exception of those classes marked as sealed, you are free to build your own classes on any of the base classes in the class library using the inheritance model in .NET.
As you explore the Framework Class Library, you will see many instances of inherited classes that override and overload class members (both of these concepts were discussed in the previous chapter). In the documentation for a specific class, you may see a method defined as Overrides:
Overrides Public Function GetYear(ByVal time As DateTime) As Integer
This example shows the method prototype for the GetYear method on the JulianCalendarClass. It shows us that this function is overridden from its base class (in this case, from the Calendar class).
Overloading is a form of overriding by providing multiple method instances that differ only in their parameter list.
As with overriding, when you explore the Framework Class Library you will notice plenty of examples of overloading. Many class constructors are overloaded to give developers the maximum choice of instantiation based on the available data.
Consider the following constructors for the TCPClient class:
Overloads Public Sub New() Overloads Public Sub New(ByVal localEP As IPEndPoint) Overloads Public Sub New(ByVal hostname As String, port As Integer)
These constructors give you the choice of how you want to instantiate a TCPClient object.
If you have been paying attention, you will have noticed by now that both Visual Basic .NET and the Framework Class Library define base data types. In other words, you have the Int32 data type defined in the System root namespace, and the Integer data type defined in Visual Basic. From a best-practice perspective, you may be asking yourself, which is the preferred method: declaring things using VB .NET intrinsics, or their actual System types?
To illustrate, both of the following lines of code are valid:
Dim SomeVar As Integer Dim AnotherVar As System.Int32
We suggest you pick whatever comes more naturally to you, and use it consistently. Using the actual Framework data types has some attraction if you are programming across multiple languages; you don't have to shift gears. On the other hand, dimensioning a variable as Integer will come much more naturally to Visual Basic developers. And of course, you don't have to worry about the repercussions of your choice: The CLR ensures that all of your code is mapped to the correct underlying data type.
Exception Handling is the process of managing errors that may be encountered during the execution of your code. The .NET runtime, and the .NET languages, supports the concept of Structured Exception Handling (SEH). These exception handlers follow a standard format that defines a Try block, a Catch block, and a Finally block.
Writing an exception handler requires you to place the code that could possibly generate an error into the Try block. In the Catch block, you place your code that deals with the error. The Finally block is where you place operations that should be performed regardless of whether an error was raised or not. The following code snippet shows a simple routine that implements its code inside of an exception handler.
Sub DoCalc(ByVal num1 As Integer, ByVal num2 As Integer) As Integer 'The exception handler is initiated with the 'try' block Try DoCalc = num1 / num2 Catch appError As Exception 'handle the error; here, we just alert the user 'through a message box. To get more detailed 'debugging level info, we could use the 'Exception.StackTrace property... MsgBox("Error:" & appError.Message) Finally Beep() End Try End Sub
Notice that the Catch statement syntax allows you to deal with the exception as an object. The class library defines an actual Exception class that allows the runtime to treat pass exceptions through as instances of the Exception class. The Exception base class is, in turn, used to derive more specialized exception classes such as the ApplicationException and SystemException classes (both defined in the System root namespace) and the WebException class (defined in the System.Net namespace). In fact, there is a fairly deep class hierarchy built from the Exception class base (see Figure 4.1).
Figure 4.1 Partial snapshot of the Exception Class Hierarchy.
As you examine the Exception class descendants, you will see that they offer methods and properties specific to a given coding scenario. They often, for instance, override the ErrorCode property to provide specific error codes for their particular scope. An exception handler with multiple catch blocks looks like this:
'The exception handler is initiated with the 'try' block Try 'code that could raise an exception goes here Catch appError As Exception 'handle the generic error Catch win32Error As Win32Exception 'handle win32 error Catch sockError As SocketException 'handle network socket error Finally 'code to run regardless of exception or not End Try
You can use the appropriate level (generalized or specialized) of exception object that is appropriate to your specific piece of code. You will often find yourself using multiple catch blocks in your code to deal with exceptions raised across different levels of the exception class hierarchy.
As we talk in-depth about the Framework classes in the chapters to come, we'll devote time to talking about these specialized exception classes in the namespaces, and the additional properties that they offer.