Professional ASP.NET 1.1 [Electronic resources]

Alex Homeret

نسخه متنی -صفحه : 244/ 31
نمايش فراداده

Visual Basic .NET

The latest version of Visual Basic is a major leap forward in terms of functionality, with several features added to take advantage of the Common Language Specification (CLS) and the CLR.

Each generation of a language brings improvements. To understand why Visual Basic .NET implements the changes it does, consider for a moment some of the problems associated with previous versions of Visual Basic:

The Visual Basic runtime libraries:These are relatively large DLLs incorporating the base functionality, and are required for all Visual Basic programs to run. Common complaints concerned the size of these DLLs, and versioning problems (different libraries for different versions of VB). You might think that these have just been replaced by the CLR, but the CLR is much more than this, and addresses far more than just VB. While size may still be considered an issue, the redistributable CLR is around 18 MB and supports multiple versions.

Poor object-oriented features:Object-oriented programming gurus criticized Visual Basic for its lack of 'proper' functionality – not providing features such as inheritance, overloading, and so on. Although these are valid points, many of the problems really stemmed from the capabilities of COM rather than Visual Basic itself.

Inability to create multi-threaded applications:With the introduction of Microsoft Transaction Server (MTS), n-tier architecture became a reality, and Visual Basic programmers started to get to grips with componentization. However, Visual Basic components were forced into an Apartment Threading model, a limitation that attracted much criticism from programmers who wanted to build multi-threaded components. Personally, I think much of this condemnation is misplaced, as I wonder how many people could actually write a fully threaded component (I'm not sure I could). Think about it – managing the threads, state, and so on, isn't easy.

All of these problems disappear in Visual Basic .NET. The runtime libraries are no longer needed because they're taken care of by the CLR, and the object-oriented features have been massively improved (partly because of CLR and CLS support) and the whole threading issue has gone away. With the CLR, you just don't need to think about threading (unless you want to). Let's look at some of the new features in Visual Basic .NET.

Object-Oriented Features

The OO features were probably one of the enhancements most requested by programmers. I remember being at a Microsoft event when Visual Basic 6 was in beta, and the most frequently asked question was whether inheritance will be supported. Since this is an intrinsic feature of the CLR, it is now supported, and classes are inheritable by default. In fact, since everything in .NET is class based, you have an enormous amount of flexibility, as you can not only extend and overload your own classes, but many system ones too.

Classes

As in previous versions of Visual Basic, classes are created using the

Class statement. However, the syntax has changed a little:

[ Public | Private | Protected | Friend | Protected Friend ]

[Shadows]

[MustInherit | NotInheritable] Class className

End Class

Note

Visual Basic still requires the underscore (

_ ) for line continuation – to make things clearer, it's not shown in the preceding syntax outline.

Let's look at the keywords in more detail:

Keyword

Description

Public

The class is publicly accessible.

Private

The class can only be accessed within the file in which it is declared.

Protected

The class is only accessible from the containing class or types derived from the containing class.

Friend

The class is only accessible from this assembly.

Protected Friend

The class is only accessible from this program or types derived from the containing class.

Shadows

The class shadows an identically named class in a base class.

Shadows is only available inside classes, structures, and interfaces.

MustInherit

This class is an abstract class, and the class members must be implemented by inheriting classes.

NotInheritable

This class is not inheritable.

Within a class, the member definition follows the same rules. Members that are not explicitly declared with a keyword are

Public by default.

For example:

Public Class Calculator

' implementation goes here

End Class

Or:

Protected MustInherit Class Calculator

' abstract implementation goes here

End Class

Methods

Methods are declared as a

Sub or a

Function , but there are improvements to fit in with the inheritance rules. The syntax for a

Sub is now:

[Overloads | Overrides | Overridable | NotOverridable | MustOverride |

Shadows | Shared]

[Private | Public | Protected | Friend | Protected Friend]

Sub subName [(parameters)]

End Sub

The syntax for a

Function is:

[Overloads | Overrides | Overridable | NotOverridable | MustOverride |

Shadows | Shared]

[Private | Public | Protected | Friend | Protected Friend]

Function functionName [(parameters)] [As type]

End Function

The various keywords are described in the following table:

Keyword

Description

Overloads

The member is overloaded, with more than one declaration existing, each with different parameters.

Overloads is not required when overloading methods in the same class, but if it is used, it must be used on all overloaded methods.

Overrides

The member overrides an identically named member from a base class. This is useful for sub-classing situations where you want to provide your own implementation of a particular member. The overridden method must have the same signature; that is, the parameters and data types must match those of the base class member.

NotOverridable

The member cannot be overridden in a derived class.

Overridable

The method can be overridden by a derived class.

MustOverride

The member must be overridden in a derived class. This implies

Overridable .

Shadows

The method shadows a method in a parent class. This means that the method in the parent class is not available, and allows creation of methods with a different signature (parameters & data types) than that of the parent. It effectively re-declares the type.

Shared

The member is shared by all instances of the class, and it exists independently of a class instance. This is equivalent to a static method in C# or C++.

Public

The member is publicly accessible.

Private

The member is only accessible within the class.

Protected

The member is only accessible from the containing class or types derived from the containing class.

Friend

The member is only accessible from this program.

Protected Friend

The member is only accessible from this program or types derived from the containing member.

For example:

Public Class Calculator

Public Function Add(Op1 As Double, Op2 As Double) As Double

Return Op1 + Op2

End Function

End Class

Note

This is an important change from previous function syntax – the value of the function is now returned using the

Return keyword, rather than by setting the function name to the value.

Properties

Properties can be implemented as

Public member variables or by using the

Property statement. For example:

Public Class Calculator

Public Op1 As Double

Public Op2 As Double Public Function Add() As Double Return Op1 + Op2 End Function End Class

The class could be used in the following way:

Dim calc As New Calculator

calc.Op1 = 123

calc.Op2 = 456

Response.Write(calc.Add())

The preceding example uses public variables. The alternative (and preferred) approach is to use

Property , the syntax of which has changed as follows:

[Default | ReadOnly | WriteOnly] Property propertyName ([parameters])

[As type]

Get

' code for getting the property

End Get

Set

' code for setting the property

End Set

End Property

A property defined as

ReadOnly can only have the

Get block. Likewise, a property with only a

Get block must be marked as

ReadOnly . The same applies for

WriteOnly and the

Set block. There is also no longer a

Let option, as

Set provides the same functionality.

For example:

Public Class Calculator

Private _op1 As Double

Private _op2 As Double

Public Property Operand1() As Double

Get

Operand1 = _op1

End Get

Set

_op1 = value

End Set

End Property

Public Property Operand2() As Double

Get

Operand2 = _op2

End Get

Set

_op2 = value

End Set

End Property

End Class

Notice the use of the keyword

value in the

Set block. This is the actual code you should type, as

value is an implicit variable that contains the value of the property being set.

Default Properties and Property Parameters

Default properties are another area of change, as they are only supported on properties with a parameter list. Therefore, you could add a property called

Result to your

Calculator class, to contain the last result of an operation, but you wouldn't be able to make it the

Default property. Hence, you can't code it like this:

Default Property Result() As Double

This stops you doing the following:

Label1.Text = MyCalc

To declare a default property, you need to have parameters (and these cannot be declared as

ByRef ). For more details, consult the Visual Basic .NET documentation supplied with the .NET SDK.

Constructors and Object Creation

The

Class_Initialize event has been removed from classes, but has been replaced with a member function called

New , which enables you to inherit from constructors.

One of the cool new features of Visual Basic .NET is the use of overloading, which is perfect for providing constructors. The

New() method is a special case for overloading, since the

Overloads keyword is not required. For example, consider a

Person class:

Public Class Person

Private _firstName As String

Private _lastName As String

Sub New()

_firstName = ""

_lastName = ""

End Sub

Sub New(firstName As String, lastName As String)

_firstName = firstName

_lastName = lastName

End Sub

Public Property FirstName() As String

' property code here

End Property

Public Property LastName() As String

' property code here

End Property

End Class

In this example there are two occurrences of

Sub New() : one without parameters, and another with. This means you can write:

Dim coolDude As New Person()

coolDude.FirstName = "Vince"

coolDude.LastName = "Patel"

Or

Dim coolDude As New Person("Vince", "Patel")

This provides a richer way of using classes and simplifies code.

Destructors and Object Destruction

Like the

Class_Initialize() method,

Class_Terminate() has also been replaced by a

Destruct() method. For example:

Sub Destruct()

' code to clean up here

End Sub

There has been a big change in the way destructors are called from previous versions of Visual Basic, and it revolves around the CLR. One of the good features of the CLR is garbage collection (GC), which runs in the background collecting unused object references, freeing you from having to ensure that you always destroy them. However, the downside is that since it's a background task, you don't know exactly when your destructor is called.

During the time of the beta releases, there was a wide discussion regarding this, resulting in an extensive paper from Microsoft about garbage collection and its effects (search the MSDN Web site for Deterministic Finalization for more details). Some people were concerned that there might be cases where they would need to guarantee something happening (such as resource cleanup) when the object is no longer in use. If this is the case, then the advice is to create a method to house this functionality, and call this method when you have finished with the class instance.

In reality, the time difference between releasing the object instance, and it being garbage collected, is likely to be very small, since the garbage collector is always running.

Inheritance

As mentioned in the previous chapter, everything in .NET is an object, so you can inherit from pretty much anything. Consider the

Person class as a base class; you could create a new class from it in the following way:

Public Class Programmer

Inherits Person

Private _avgHoursSleepPerNight As Integer

Public Sub New()

MyBase.New()

End Sub

Public Sub New(firstName As String, lastName As String)

MyBase.New(firstName, lastName)

End Sub

Public Sub New(firstName As String, lastName As String, _

hoursSleep As Integer)

MyBase.New(firstName, lastName)

_avgHoursSleepPerNight = hoursSleep

End Sub

Public Property AvgHoursSleepPerNight() As Integer

Get

AvgHoursSleepPerNight = _avgHoursSleepPerNight

End Get

Set

_avgHoursSleepPerNight = value

End Set

End Property

End Class

This class extends the existing

Person class and adds a new property. Let's look at the way it does this.

First, after the class declarations comes the

Inherits statement, where the base class we are inheriting from is specified:

Public Class Programmer
Inherits Person

Next, come the definitions for the existing constructors. Our class provides an extra one, so we need to overload the base class constructors. Notice how the definitions of these match the definitions in the base class, and how we call the constructor of the base class using

MyBase . We are not changing the existing constructors, just adding our own, so we just want to map functionality to the base class:

Public Sub New()
MyBase.New()
End Sub
Public Sub New(firstName As String, lastName As String)
MyBase.New(firstName, lastName)
End Sub

Now we can add our extra constructor, which calls one of the previous constructors and then sets the additional property:

Public Sub New(firstName As String, lastName As String, _
hoursSleep As Integer)
MyBase.New(firstName, lastName)
_avgHoursSleepPerNight = hoursSleep
End Sub

Finally, we add the definition of the new property:

Public Property AvgHoursSleepPerNight() As Integer
Get
AvgHoursSleepPerNight = _avgHoursSleepPerNight
End Get
Set
_avgHoursSleepPerNight = value
End Set
End Property

In object-oriented terms, this is standard stuff, but it's new for Visual Basic and provides a great way to promote code reuse.

Classes and Interfaces

An interface is the description of the methods and properties a class will expose – it's an immutable contract with the outside world. The interface doesn't define any implementation – just the methods and properties. Derived classes then have to provide the actual implementation.

In Visual Basic .NET you automatically get a default interface that matches the class methods and properties, but there may be times when we want to explicitly define the interface. One good example of this is that when creating .NET-serviced components, the interface can be used to provide versioning features. See Chapter 23 for more details on this.

To create an interface, the

Interface construct is used as follows:

Public Interface IPerson

Property FirstName() As String

Property LastName() As String

Function FullName() As String

End Interface

As you can see, there is no implementation specified here. By convention, the interface name is the class name preceded by

I , although this isn't enforced. To derive a class from an interface, the

Implements keyword is used on the class:

Public Class Person

Implements IPerson

Private _firstName As String

Private _lastName As String

Public Property FirstName() As String Implements IPerson.FirstName

' implementation goes here

End Property

Public Property LastName() As String Implements IPerson.LastName

' implementation goes here

End Property

Public Function FullName() As String Implements IPerson.FullName

Return _firstName & " " & _lastName

End Function

End Class

Note

Both the class, and the methods and properties, have to specify their implementation interface.

Multiple inheritance is allowed only in an interface. For example:

Public Interface Person

Inherits IPerson

Inherits ICleverPerson

End Interface

Language Changes

Along with the object-oriented features, there have been many changes to the language. We won't go into exhaustive detail here (it's well covered in the documentation), but here are some things to watch out for:

Array bounds:The lower bound of an array is always

0 , and cannot be changed. The

Option Base statement is not supported.

Array declaration:

ReDim can only be used if the array has already been declared.

Array sizes:Arrays do not have a fixed size (although the number of dimensions is fixed). For example.

Dim ConnectionTimes(10) As Date

This defines an array with an initial size of 11 elements. Arrays can also be populated on declaration:

Dim ConnectionTimes() As Date = {"10:30", "11:30", "12:00", "06:00"}

String length:The fixed-width string is not supported unless the

VBFixedString attribute is used.

Variants:The

Variant data type is no longer supported, being replaced by a more generic

Object . The corresponding

VarType function is also not supported, as the

Object has a

GetType method.

Data types:The

Currency data type is replaced by

Decimal . The

Integer type is now 32 bits, with

Short being 16 bits and

Long being 64 bits.

Short cut operators:A new short form of addition and assignment has been added. For example.

counter += 1

name &= " Sussman"

Default properties:As mentioned earlier, default properties are not supported, unless they take parameters.

Variable declaration:When declaring multiple variables on the same line, a variable with no data type takes the type of the next declared type (and not

Variant as was the case in VB6). For example, in the following declarations

Age is an

Integer .

Dim Age, Hours As Integer

Dim Name As String, Age, Hours As Integer

Variable scope:Block scope is now supported, so variables declared within blocks (such as

If blocks) are only visible within the

If block. In Visual Basic 6, variables could be declared anywhere, but their scope was the entire method.

Object creation:The

As New keywords can be used freely on the variable declaration line. There is no implicit object creation, so objects that are

Nothing remain set to

Nothing unless an explicit instance is created.

Procedure parameters:The rules for parameter passing and optional parameters have changed. See the section on Parameters later for more information on this.

Procedure calls:Parentheses are now required on all procedure calls, not just functions.

Function return values:The return value from a function is now supplied with the

Return statement, rather than by setting the function name to the desired value.

While loops:The

Wend statement has been replaced with

End While .

String and Variant functions:The string manipulation functions that had two types of call (

Trim returned a

Variant and

Trim$ returned a

string ) are replaced with overloaded method calls.

Empty and Null:The

Empty and

Null keywords have their functionality replaced by

Nothing .

There are many other changes, some of which don't really affect ASP.NET programmers. For a full list, consult the Visual Basic .NET documentation, or see Wrox's Professional VB.NET, 2nd Edition, ISBN: 0-7645-4400-4.

References

Since you're freed from using a set design tool, some of the features you are used to now require a bit more typing. One example of this is referencing other components. In Visual Basic 6, to access COM components you select References from the Project menu. There's something similar in Visual Studio .NET to reference assemblies (or even COM components), but if you're using Notepad, you have to provide the reference yourself. This is done using the

Imports keyword. For example:

Imports System

Imports MyComponent

It's also possible to alias references using the following syntax:

Imports aliasName = Namespace

If an alias is used, the alias must be included in references to classes that the namespace contains. For example, if you have a namespace called

MyComponent containing a class called

MyClass , and import the namespace like this:

Imports foo = MyComponent

You can't then access the class like this:

Dim comp As MyClass

You have to use the following syntax:

Dim comp As foo.MyClass

Structured Exception Handling

One of the best new features of .NET is a unified structured exception-handling framework, which extends to Visual Basic .NET. Although

On Error is still supported, a far better way of handling errors is to use the new

Try …

Catch …

Finally structure. The way it works is simple, with each of the statements defining a block of code to be run.

The syntax is:

Try

' code block to run

[

Catch [exception [As type]] [When exception]

' code to run if the exception generated matches

' the exception and expression defined above

[Exit Try]

]

Catch [exception [As.type]] [When expression]

' code to run if the exception generated matches

' the exception and expression defined above

[Exit Try]

[Finally

' code that always runs, whether or not an exception

' was caught, unless Exit Try is called

]

End Try

This allows you to bracket a section of code and then handle generic or specific errors. For example:

Try

' connect to a database and

' retrieve some data

' ... code left out for clarity ...

Catch exSQL As SQLException

ErrorLabel.Text = "SQL Error: " & exSQL.ToString()

Catch ex As Exception

ErrorLabel.Text = "Other error: " & ex.ToString()

Finally

FinishedLabel.Text = "Finished"

End Try

You can have multiple

Catch blocks, to make our error handling specific to a particular error. Always put the most specific

Catch blocks first and the more generic ones last, as the

Catch blocks are tried in the order they are declared.

The

Throw statement can be used to throw your own errors, or even re-raise errors.

Errors and exceptions are covered in detail in Chapter 22.

Data Types and Structures

There are three new data types:

Char : for unsigned 16-bit values.

Short : for signed 16-bit integers. This is the equivalent to the current Visual Basic

Integer (in Visual Basic .NET the

Integer is now 32-bits and the

Long 64-bits).

Decimal : for signed integers.

Custom types are now provided by the

Structure statement, rather than the

Type statement. The syntax is:

[Public | Private | Friend] Structure structureName

End Structure

For example:

Public Structure Person

Public FirstName As String

Public LastName As String

Private Age As Integer

End Structure

The use of structures is unified with classes, enabling structures to not only contain member variables, but also methods:

Public Structure Narcissist

Public FirstName As String

Public LastName As String

Private RealAge As Integer

Public Function Age() As Integer

Return RealAge – 5

End Function

End Structure

Whether you use classes or structures is purely a coding and design decision, but the close linking of the two types provides added flexibility.

Parameters

Several things have changed regarding passing parameters to procedures. The most important is that parameters now default to

ByVal . To achieve reference parameters, you must explicitly put

ByRef in front of the parameter name.

Secondly, as mentioned earlier, all method calls with parameters must be surrounded by parentheses. The previous versions of Visual Basic had the inconsistency that parentheses were required for functions but not subroutines. For example, the following is no longer valid:

MyMethod 1, 2, "foo"

Instead, you must use:

MyMethod(1, 2, "foo")

For optional parameters, you now have to specify a default, and the

IsMissing() method is removed. For example, you cannot write:

Sub MyMethod(Name As String, Optional Age As Integer)

If IsMissing(Age) Then

...

You have to supply a default:

Sub MyMethod(Name As String, Optional Age As Integer = -1)

Debugging and Message Boxes

Although not relevant to ASP.NET pages, there are two things that might hit you if you are using Visual Studio .NET:

The

Print method of the

Debug object has been replaced by four methods –

Write() ,

WriteIf() ,

WriteLine() , and

WriteLineIf() .

The

MsgBox statement has been replaced with the

Show method of the

MessageBox object.

Debugging is covered in detail in Chapter 22.

Backward Compatibility

To ease the transition from Visual Basic 6 to Visual Basic .NET, you can reference the

Microsoft.VisualBasic.Compatibility.VB6 namespace, which provides access to much of the removed or changed functionality. It's probably best not to overuse these compatibility features, though. The changes to the language have been made not only to improve it, but also to bring it in line with the CLS and the other .NET languages.