By Scott Mauvais, MCSD
Originally published April 4, 2002
Confession: I wrote my first application with Microsoft Visual Basic .NET about a month ago. Not that I'm new to Microsoft Visual Basic??I've been using it regularly since version 2?but for some reason I never got around to playing with Visual Basic .NET until now. One of the main reasons for thedelay is that I never became very proficient in Microsoft Visual C++? .NET and I decided it was high time I learned one of the C-language derivatives. So I decided that as I worked my way through the Microsoft .NET Framework I would force myself to learn it through Visual C#? .NET.
After spending nearly 18 months with C#, I am still driven to the help system at least once a week to figure out the syntax for something I know exactly how to do in Visual Basic. So, a few weeks ago when the opportunity came along to develop an application in Visual Basic .NET, I jumped on it. The first thing I did was peruse a review copy of Programming Microsoft Visual Basic .NET (Core Reference) by Francesco Balena. This book should be generally available by the time you read this, and I highly recommend picking up a copy to help jump-start your trek down the Microsoft .NET path and learn how to use all the exciting new features in Visual Basic .NET. To get a feel for what is in the book and to make sure it is right for you, check out the book's table of contents and read the sample chapter.
You know what my first impression of Visual Basic .NET was? I couldn't believe how easy it was. Over the past few months I have read?as I'm sure you have also?a handful of articles by various techno-weenie pundits decrying the complexity of Visual Basic .NET and claiming that Visual Basic developers would not, or could not, upgrade their skill sets. Initially I just assumed that they couldn't come up with anything interesting to write about, so they decided to try to conjure up something new about Visual Basic to whine about ever since the Fitch & Mather Stocks sample app demonstrated three years ago that performance was not an issue with Visual Basic. (By the way, there is now a .NET implementation of Fitch & Mather Stocks.) But now that I have used Visual Basic .NET some, I must say I'm a bit irked that they have sold us Visual Basic developers so short. With everyone touting the ease of developing for the .NET Framework and the productivity improvements in Microsoft Visual Studio? .NET, it's hard to imagine what they see as so difficult in Visual Basic .NET that would prevent us developers from coming up to speed on it.
Clearly there are some new things in Visual Basic .NET that you will need to learn, and spending a couple hours with Francesco Balena's Programming Microsoft Visual Basic .NET (Core Reference) certainly helped me out. That said, most of the changes are enhancements we have been requesting for some time such as real object orientation, thread support, and better error-handling and monitoring, so it is somewhat disingenuous to claim that Visual Basic .NET is too hard for us timid Visual Basic developers when Microsoft simply gave us exactly what we asked for. There are some syntax changes that may cause you some trouble if you have been using Visual Basic for a long time (like since it was GW-Basic.) Most syntax issues are language idiosyncrasies that have long been deprecated such as GoSub (when's the last time you used that!) so I doubt they will be much of an issue for developers. For the rest, I found I learned how to resolve most of them on the fly when either the IDE's autocorrect feature fixed my code by itself (like when I tried to use the Set statement to assign an object reference) or when the compiler complained (such as when I used an optional parameter and the compiler reminded me that I must now assign a default value).
Now that I have (hopefully) dispelled the misconception that Visual Basic .NET is hard, I thought I would spend the rest of the article walking you through a key new object-oriented feature: inheritance. I decided to skip the discussion of error handling and monitoring because Microsoft recently released two white papers on the subject: Monitoring in .NET Distributed Application Design by Amitabh Srivastava and Edward Jezierski and Exception Management in .NET by Kenny Jones and Edward Jezierski (again!). Better yet, you can even download the Exception Management Application Block for .NET (yup, Jezierski is a co-author on that one, too). As for threading, that is a larger topic that is not specific to Visual Basic .NET, so I will tackle it in a separate article.
One of the big hassles with Microsoft Visual Basic 6.0 was the lack of true inheritance. Sure, Visual Basic 6.0 supported the Implements keyword, which provided interface inheritance that was often good enough, but many times I have wanted true implementation inheritance. Visual Basic .NET gives it to us. So what is the difference? The best way to understand the two forms of inheritance is by looking at an example.
As I am watching the California Primary election returns, I call my sample class CElection and give it three methods: GetElectionDay(), CastVote(), and CountCote(). To make things simple, GetElectionDay() will take a year as the argument and will return (surprise!) the date of the election for that year. Since it is my sample, I get to make the rules and in my state we vote every year on the first Tuesday after the first Monday in November. CastVote() is pretty simple, it takes a candidate's name and pretends to record a vote for or her or him in the database but really does nothing. CountCote() is equally simply; it declares me the winner.
That Was Then
Okay, enough of narrative; let's look at some code and see how to accomplish this in Visual Basic 6.0. First I start out with an empty class and define the interface.
'-- IElectionOption Explicit
'-- Interface only, no implementationPublic Function
(Optional ByVal Year As Long = 0) As DateEnd Function
Public Sub CastVote(ByVal p_sCandidateName As String)End
Public Function CountVotes() As StringEnd Function
Next I implement the interface in a separate class. For the sake of brevity, I won't include the actual code to implement the methods here; you can download it from my Web site if you want, but it is fairly similar to the Visual Basic .NET code below.
'-- CElectionOption ExplicitImplements IElection
'-- Provide ImplementationPrivate Function
(Optional ByVal p_lYear As Long = 0) As Date
'-- Phone a friend to get the dateEnd Function
Private Sub IElection_CastVote(ByVal p_sCandidateName As
String) '-- C:\MOVE YourVote NUL:End
Private Function IElection_CountVotes() As
String '-- Declare me the winnerEnd
Finally, I need to write some code to consume my class. To keep things simple, I remove all the error-handling code.
'-- frmElectionOption Explicit
'-- Actually use the codePrivate Sub
cmdGetElectionDate() Dim oElection As
IElection Set oElection = New
Private Sub cmdCastVote() Dim oElection As
IElection Set oElection = New
Hard-coded, you get no choice Call
Private Sub cmdCountVotes() Dim oElection
As IElection Set oElection = New
The key thing to notice here is that you must declare your variable as the interface class (IElection) and then instantiate it as the implementation class (CElection).
In the example here, I get the is a relationship required relationship because I can still use my derived class (CElection) in any application that is compatible with the base class (IElection) as demonstrated by the following snippet:
Dim oElection As IElection
Set oElection = New CElection
In other words, CElection is an IElection.
Now assume that in my state I need to hold a special election for some reason. (I don't know why; I won with 100% of the vote.) Everything is the same (I still throw away all votes, and I still guarantee that I'm the winner), but the Election Day is four weeks later in the special election. Because Visual Basic 6.0 only offers interface inheritance I need to re-implement the CastVote() and CountVotes() methods even though nothing changed. To do this I utilize ?copy-and-paste inheritance,? which is built into every version of Microsoft Windows? since version 1.0, and create a file by copying the CElection.cls to CSpecialElection.cls files. Next I fire up Visual EDLIN and fiddle around with the specifics of the GetElectionDay() method to add 28 days to the return value. Finally, I add the new file to my project and call the class CSpecialElection.
Not too burdensome; but what happens when my opponents suspect there is something fishy, and I need to add a Contest() method? Well, I would have to edit the CElection, CElection, and CElection classes. This can quickly become a major pain if I have based several classes on a single interface.
Fortunately, Visual Basic .NET offers implementation inheritance.
This Is Now
With Visual Basic NET, I can define a class once and directly reuse it, including the implementation, in other classes, as shown in this example.
Class CElection Public Overridable Function GetElectionDay _
(Optional ByVal p_lYear As Long = 0) As Date
DimdRetVal As Date Dim fMonday As Boolean = False
'-- If no year passed, assume current year If p_lYear = 0 Then
p_lYear = Year(Now) End If
'-- Start with Nov 1 and add days until we find a Tues. '-- After a Monday dRetVal = CDate("11/1/" & p_lYear.ToString)
If Weekday(dRetVal, FirstDayOfWeek.Sunday) = vbMonday Then
fMonday = True End If
dRetVal = DateAdd(DateInterval.Day, 1, dRetVal)
Loop Until fMonday _
And Weekday(dRetVal, FirstDayOfWeek.Sunday) = vbTuesday
GetElectionDay = dRetVal End FunctionEnd Class
I included the full listing for the GetElectionDay() method so that you can get a feel for the syntax of Visual Basic .NET. Because there is nothing special in the CastVote() and CountVotes() methods, I skipped them. Of course, if you are interested, you can download the complete source for this from my Web site. Everything should be pretty straightforward. The one thing you will notice is the Overridable keyword. As the developer of a class, you have full control over whether you want to allow your methods and properties to be overridden. If you want to specifically prevent your implementation from being overridden, use the NotOverridable keyword. By default, all public members are NotOverridable unless you specify otherwise. The compiler will prevent you from overriding any method (or property) that is declared as NotOverridable or a public member that is not explicitly marked as Overridable.
Now that we have defined our base class, let's look at how to derive a new class from it.
Class CSpecialElection Inherits CElection Overrides Function GetElectionDay _
(Optional ByVal p_lYear As Long = 0) As Date
GetElectionDay = DateAdd(DateInterval.Day, 28,_ MyBase.GetElectionDay(p_lYear)) End FunctionEnd Class
Pretty simple: Six lines of code if you count all the formatting and the function declaration. There are three important things about this piece of code that warrant further attention.
First is the Inherits line. This simply causes the class, CSpecialElection in this case, to inherit all the non-private members of the base class, CElection.
Next, the Overrides keyword is the corollary to the Overridable keyword in the base class and instructs the compiler to use the implementation in the derived class rather than the base class. If you don't specifically override a method or a property, the implementation in the base class will be used.
Finally, the MyBase keyword acts just like an object-referencing base class. So in the line
GetElectionDay = DateAdd(DateInterval.Day, 28,
I am calling into my base class, getting the standard Election Day, and using the DateAdd function to add 28 days to the result.