Spracherweiterungen von Visual Basic 2005

Veröffentlicht: 22. Mrz 2005

Von Matthew MacDonald

VB 2005 Developer

Die Entwickler von Microsoft arbeiten angestrengt an der neuen Version von .NET. Denn was wäre eine neue Programmierplattform ohne eine Optimierung der Sprache? In diesem Artikel beschreibt Matthew MacDonald die Änderungen in der neuesten Version von Visual Basic, derzeit als Visual Basic 2005 bezeichnet.

(Dieser Artikel basiert auf Materialien aus dem demnächst bei O'Reilly erscheinenden Buch VB 2005 Developer's Notebook von Matthew MacDonald.)

Die Entwicklung moderner Anwendungen wurde durch die Veröffentlichung von .NET 1.0 revolutioniert. Zudem wurden erstmalig nach fast einem Jahrzehnt grundlegende Änderungen an der Sprache Visual Basic vorgenommen. Beispielsweise hat Microsoft gängige Aufgaben wie das Erstellen von Objekten, die Deklaration von Strukturen, das Anzeigen von Formularen und die Verwendung von Arrays grundlegend geändert. (Eine kritische Übersicht der Änderungen von Visual Basic 6.0 bis Visual Basic .NET finden Sie unter www.mvps.org/vb/index2.html?rants/vfred.htm (in Englisch).)

Glücklicherweise sind die Änderungen in .NET 2.0 nicht so erschütternd. Stattdessen wurde die Sprache weiterentwickelt, ohne die Ausführbarkeit vorhandenen Codes zu beeinträchtigen. Viele Änderungen ermöglichen die Verwendung von Features, die in C# bereits verfügbar sind. Es gibt jedoch neue Features, die in beiden Sprachen noch nicht vorhanden sind. In diesem Artikel werden die folgenden nützlichsten Änderungen erläutert:

  • Überladen von Operatoren

  • Partielle Klassen

  • Die Anweisung Continue

  • Die Anweisung Using

  • Zugreifen auf unterteilte Eigenschaften

  • Generische Klassen

Ein Feature, das in diesem Artikel nicht behandelt wird, ist das Objekt My. Dabei handelt es sich um eine Art zentrales Repository nützlicher Funktionen. Das Objekt My ist genau genommen keine Änderung an der Sprache Visual Basic. Es handelt sicher eher um Verknüpfungen mit Features, die in VB codiert sind. In zukünftigen Artikeln finden Sie ausführliche Informationen zum Objekt My.

Überladen von Operatoren

Sie kennen die arithmetischen Operatoren, die für Addition (+), Subtraktion (-), Division (/) und Multiplikation (*) verwendet werden. In VB.NET 1.0 werden diese Operatoren für numerische Datentypen verwendet. Bei anderen Objekten haben sie üblicherweise keine Bedeutung. Dies ist in C# jedoch nicht der Fall. Damit können Entwickler benutzerdefinierte Klassen erstellen, die diese und einige weitere Operatoren für eigene Zwecke verwenden.

Folgende Aussage dazu stammt von einem der Entwickler des VB.NET-Compilers: "Die Überladung von Operatoren war leider nicht Bestandteil von VB.NET 1.0, da wir nicht genügend Zeit dafür hatten". VB 2005 schließt diese Lücke.

Folgendes Beispiel ist für das Verständnis der Operatorüberladung hilfreich. Sehen Sie sich folgenden Code an, der in VB.NET 1.0 unzulässig ist.

Dim ShortSpan, LongSpan, TotalSpan As TimeSpan
ShortSpan = TimeSpan.FromMinutes(100)
LongSpan = TimeSpan.FromDays(14)
TotalSpan = ShortSpan + LongSpan
Console.WriteLine(TotalSpan.TotalMinutes)

Wichtig ist die vorletzte Zeile, in der der Operator + verwendet wird, um die Werte zweier TimeSpan-Objekte zu addieren. Das funktioniert, da der Compiler bei der Analyse des Ausdrucks ShortSpan + LongSpan erkennt, dass ShortSpan den Datentyp TimeSpan hat, in dessen zugrunde liegender Klasse der Operator + als spezielle Funktion definiert ist. Mit diesem Wissen kann der Code ungefähr folgendermaßen übersetzt werden (es handelt sich um gültige VB.NET 1.0-Syntax):

TotalSpan = ShortSpan.Add(LongSpan)

Um einen Operator in Visual Basic 2005 zu überladen, müssen Sie in Ihrer Klasse (oder Struktur) eine Methode für diesen definieren. Diese Methode muss mit den Schlüsselwörtern Public Shared Operator gefolgt vom Operator (z. B. +) deklariert werden. Im folgenden Beispiel wird eine Methode für den Additionsoperator (+) gezeigt:

Public Shared Operator+(objA As MyClass, 
  objB as MyClass) As MyClass
    ' (Code goes here.)
End Operator

Jede Operatormethode akzeptiert zwei Parameter, die beiden Werte, die durch den Operator verknüpft werden. Je nach Klasse und Operator kann die Reihenfolge von Bedeutung sein (z. B. bei der Division).

Das Überladen von Operatoren ist für Geschäftsobjekte möglicherweise nicht besonders sinnvoll. Es ist jedoch für die Modellierung mathematischer Strukturen wie Vektoren, Matrizen, komplexen Zahlen und Brüchen sehr praktisch. In Codebeispiel 1 wird gezeigt, wie Sie in Visual Basic arithmetische Operatoren überladen können, so dass Sie ein Point-Objekt (wie es auch in den GDI+-Namespaces von .NET Framework definiert ist) addieren und subtrahieren können.

Codebeispiel 1: Die Klasse "Point" mit Operatorüberladung.

Public Class Point

    Public X As Integer
    Public Y As Integer

    Public Sub New(ByVal x As Integer, _
      ByVal y As Integer)
        Me.X = x
        Me.Y = y
    End Sub

    Public Shared Operator +(ByVal x As Point, _
      ByVal y As Point) As Point
        Return New Point(x.X + y.X, x.Y + y.Y)
    End Operator

    Public Shared Operator -(ByVal x As Fraction, _
      ByVal y As Fraction) As Point
        Return New Point(x.X - y.X, x.Y - y.Y)
    End Operator

    ' Get a string representation of the Point.
    Public Overrides Function ToString() As String
        Return "(" & Me.X.ToString & ", " & _
          Me.Y.ToString & ")"
    End Function

End Class

Üblicherweise wird für Parameter und Rückgabewert einer Operatormethode derselbe Datentyp verwendet. Es gibt jedoch keinen Grund, nicht mehr als eine Version einer Operatormethode zu erstellen (Überladung), so dass ein Objekt in Ausdrücken mit verschiedenen Datentypen verwendet werden kann.

Partielle Klassen

Partielle Klassen sind nicht so Aufsehen erregend wie die Operatorüberladung, jedoch genauso nützlich. Mithilfe von partiellen Klassen können Sie eine Klasse in separate Dateien aufteilen. Sie müssen lediglich dieselbe Klasse an mehreren Orten definieren und jeweils das Schlüsselwort Partial in der Deklaration verwenden. Im folgenden Beispiel wird die Klasse TestClass in zwei Teilen definiert:

Partial Public Class TestClass
    Public Sub TestMethodA()
        Console.WriteLine("Method A called.")
    End Sub
End Class

Partial Public Class TestClass
    Public Sub TestMethodB()
        Console.WriteLine("Method B called.")
    End Sub
End Class

In diesem Beispiel stehen beide Deklarationen nacheinander in derselben Datei. Die beiden Teildefinitionen von TestClass können jedoch innerhalb desselben Projekts in unterschiedlichen Quellcodedateien stehen. (Die einzige Einschränkung besteht darin, dass die beiden Teile nicht in separaten Assemblys oder Namespaces definiert werden können.) Sie können die Definition der Klasse TestClass noch weiter unterteilen, es gibt hierfür praktisch keine Begrenzung.

Wenn Sie die Anwendung erstellen, fügt Visual Studio .NET jede Teildefinition von TestClass in eine vollständige Klasse mit zwei Methoden, TestMethodA() und TestMethodB(), zusammen und kompiliert diese. Sie können beide Methoden, wie unten gezeigt, auf dieselbe Weise verwenden:

Dim Obj As New TestClass()
Obj.TestMethodA()
Obj.TestMethodB()

Zusammenfassend dient der Einsatz von partiellen Klassen folgenden beiden Zwecken:

  • Extrem große Klassen können in kleinere, besser zu verwaltende Teile unterteilt werden.

  • Weniger wichtiger Code, z. B. automatisch erzeugter Designercode, kann verborgen werden.

Der zweite Aspekt ist der wichtigste und der Grund für die Einführung von partiellen Klassen in .NET-Sprachen wie VB 2005 und C#. Wenn Sie beispielsweise ein .NET-Formular in Visual Studio 2005 erstellen, steht der Code zur Ereignisbehandlung in der Quellcodedatei für das Formular. Der Designercode zur Erstellung und Konfiguration der Steuerelemente und zur Verbindung mit den Ereignishandlern ist jedoch nicht sichtbar. Das liegt daran, dass der Code in einer separaten Datei und für die Ansicht nicht zur Verfügung steht. Somit kann er nicht versehentlich manipuliert werden. (Sie können den Code natürlich anzeigen, wenn Sie sicher sein möchten, dass er tatsächlich vorhanden ist. Wählen Sie dazu im Visual Studio-Menü Project (Projekt) und anschließend Show All Files (Alle Dateien anzeigen). Daraufhin wird eine neue Datei mit den anderen Definitionen der Klasse angezeigt. Wenn Sie beispielsweise das neue Formular Formular1 erstellen, werden automatisch die Dateien Formular1.vb für Ihren Code und Formular1.Designer.vb für den automatisch erzeugten Teil erstellt. Noch eine letzte Warnung: Dieses Feature ist nicht in allen frühen Alphaversionen von Visual Studio 2005 implementiert.)

Die Anweisung "Continue"

Die Sprache Visual Basic bietet eine Reihe von Anweisungen zur Ablaufsteuerung für die Programmausführung. Mit Return können Sie beispielsweise eine Funktion und mit Exit eine Schleife verlassen. Es gab jedoch bis VB 2005 keine Möglichkeit, zur nächsten Iteration einer Schleife zu springen. Durch die in VB 2005 eingeführte Anweisung Continue wird diese Lücke geschlossen.

Die Anweisung Continue scheint zunächst weniger nützlich zu sein, erweist sich jedoch schnell als sehr komfortabel. Die Anweisung Continue ist in drei Varianten vorhanden: Continue For, Continue Do und Continue While. Jede wird mit einem anderen Schleifentyp verwendet (For ... Next, Do ... Loop oder While ... End While).

Das folgende Codebeispiel dient zur Veranschaulichung der Arbeitsweise von Continue:

For i = 1 to 1000
    If i Mod 5 = 0 Then
        ' (Task A code.)
        Continue For
    End If
    ' (Task B code.)
Next

Die Schleife im Beispiel wird 1.000-mal durchlaufen und dabei jeweils der Zähler i inkrementiert. Immer wenn i durch 5 teilbar ist, wird der Code von Task A ausgeführt. Anschließend wird die Anweisung Continue For ausgeführt, der Zähler inkrementiert und die Ausführung am Anfang der Schleife fortgesetzt. Der Code von Task B wird übersprungen.

In diesem Beispiel ist die Anweisung Continue nicht wirklich erforderlich, da das gleiche Ergebnis auch mit anderen bedingten Anweisungen erzielt werden kann. Wenn es sich jedoch um einen komplexen Codeabschnitt handelt, in dem eine Reihe verschiedener Tests durchgeführt werden muss, kann sich die Anweisung Continue zum Verlassen des Abschnitts als sehr praktisch erweisen.

Es gibt eine Einschränkung bezüglich der Anweisung Continue. In einer geschachtelten Schleife verhält sich die Anweisung möglicherweise nicht wie gewünscht. Wenn Sie zwei Schleifen vom selben Typ ineinander schachteln, gibt es keine eindeutige Möglichkeit sich auf die äußere Schleife zu beziehen. Somit bezieht sich die Anweisung Continue immer auf die innere Schleife.

Wenn Sie jedoch unterschiedliche Schleifentypen verwenden, besteht dieses Problem nicht. Wenn Sie wie im folgenden Beispiel eine For-Schleife in einer Do-Schleife verwenden, können Sie mit Continue For zur nächsten Iteration der inneren Schleife und mit Continue Do zur nächsten Iteration der äußeren Schleife springen:

Do
    For i = 1 to 1000
        If i Mod 5 = 0 Then
            ' (Task A code.)

            ' The next line skips Task B and Task C.
            Continue Do
        End If
        ' (Task B code.)
    Next
    ' (Task C code.)
Loop Until StopLoop

Diese Vorgehensweise funktioniert auch, wenn Sie eine Do-Schleife in einer For-Schleife verwenden.

Die Anweisung "Using"

In .NET muss unbedingt beachtet werden, dass Objekte, die nicht verwaltete Ressourcen verwenden (z. B. Dateihandles, Datenbankverbindungen, Grafiken usw.), diese schnellstmöglich wieder freigeben. Daher müssen solche Objekte die Schnittstelle IDisposable implementieren und die Methode Dispose() bereitstellen, die zur sofortigen Freigabe von Ressourcen aufgerufen werden kann.

Sie müssen jedoch daran denken, die Methode Dispose() oder eine andere Methode aufzurufen, die Dispose() aufruft, z. B. Close(). VB 2005 bietet mit der Anweisung Using einen neuen Schutzmechanismus, mit der Sie sicherstellen können, dass Dispose() immer aufgerufen wird.

Die Anweisung Using wird in Form einer Blockstruktur verwendet. In der ersten Zeile, der Deklaration des Using-Blocks, legen Sie das entfernbare Objekt fest. Normalerweise erstellen Sie gleichzeitig auch das Objekt mit dem Schlüsselwort New. Dann schreiben Sie den Code, in dem das entfernbare Objekt verwendet wird, in den Using-Block. Im folgenden Codefragment wird gezeigt, wie eine neue Datei erstellt wird, in die Daten geschrieben werden:

Using NewFile As New _
  System.IO.StreamWriter("c:\MyFile.txt")
    NewFile.WriteLine("This is line 1")
    NewFile.WriteLine("This is line 2")
End Using

' The file is closed automatically. 
' The NewFile object is no longer available here.

Im Beispiel wird sofort nach Verlassen des Using-Blocks die Methode Dispose() für das Objekt NewFile aufgerufen, um das Dateihandle freizugeben. Glücklicherweise wird in .NET sichergestellt, dass die Ressource entfernt wird, unabhängig davon, wie Sie den Using-Block verlassen. Das ist auch der Fall, wenn eine nicht behandelte Ausnahme auftritt.

Zugreifen auf unterteilte Eigenschaften

In VB gibt es drei Zugriffsebenen. Dies sind (geordnet nach den Zugriffsbeschränkungen, beginnend mit den geringsten Einschränkungen):

  • Public (für alle Klassen in allen Assemblys verfügbar)

  • Friend (für den gesamten Code in allen Klassen in der aktuellen Assembly verfügbar)

  • Private (nur für Code in derselben Klasse verfügbar)

Nehmen Sie an, Sie erstellen eine DLL-Komponente, die von einer anderen Anwendung verwendet werden soll. Sie könnten die Eigenschaft Status definieren, die die Clientanwendung zum Lesen benötigt. Daher legen Sie für die Eigenschaft die Zugriffsebene Public fest:

Public Property Status() As Integer
    Get
        Return _Status
    End Get
    Set(ByVal value As Integer)
        _Status = value
    End Set
End Property

Im Beispiel erfolgen Lese- und Schreibzugriffe auf die Eigenschaft auf derselben Zugriffsebene. Dies ist eine Anforderung in VB.NET 1.0. Problematisch daran ist, dass die Clientanwendung den Wert der Eigenschaft Status ändern kann. Dies ergibt jedoch keinen Sinn. Sie könnten eine schreibgeschützte Eigenschaft definieren, indem Sie den Code zum Setzen der Eigenschaft weglassen. Dann könnten jedoch auch andere Klassen in Ihrer Komponenten-Assembly den Status nicht ändern.

Die Lösung in VB 2005 besteht darin, für das Setzen der Eigenschaft die Zugriffsebene Friend festzulegen. Der entsprechende Code sieht folgendermaßen aus:

Public Property Status() As Integer
    Get
        Return _Status
    End Get
    Friend Set(ByVal value As Integer)
        _Status = value
    End Set
End Property

Generische Klassen

Zu den Schlüsselprinzipien der objektorientierten Programmierung gehört es, Ihre Lösungen so abstrakt und allgemein wie möglich zu halten, so dass sie in verschiedenen Szenarios wieder verwendet werden können. Unglücklicherweise ist das nicht immer einfach. Die Programmierer stehen vor der Herausforderung, die Klassen einerseits allgemein zu halten, damit sie wieder verwendet werden können. Andererseits müssen sie spezifisch genug sein, um Fehler abzufangen und eine gute Leistung zu gewährleisten.

Betrachten Sie beispielsweise Auflistungen. Ein guter objektorientierter Programmierer würde eher eine allgemeine Collection-Klasse entwickeln, die mit beliebigen Objekttypen verwendet werden kann, anstatt für jeden spezifischen Objekttyp (z. B. OrderItemCollection) eine separate Auflistung zu erstellen. Eine allgemeine Collection ist sicherlich einfacher, eleganter und erfordert weniger Arbeit als eine Menge benutzerdefinierter Klassen, wie OrderItemCollection. Andererseits lassen Überlegungen zur Leistung und Typsicherheit eine allgemeine Lösung weniger wünschenswert erscheinen. Anders gesagt, wenn Sie eine allgemeine Klasse Collection zum Speichern von OrderItem-Objekten verwenden, wie können Sie dann sicherstellen, dass niemand andere Objekttypen einfügt und dadurch möglicherweise schwer erkennbare Fehler verursacht?

Die Lösung in .NET 2.0 heißt generische Klassen. Generische Klassen sind Klassen, die dem Typ entsprechend parametrisiert werden. Mit anderen Worten, Sie erstellen eine Klassenvorlage, die jeden Typ unterstützt. Beim Instanziieren dieser Klasse geben Sie dann den zu verwendenden Typ an. Damit ist das Objekt auf den gewählten Typ festgelegt. Generische Klassen sind in der Common Language Runtime implementiert und stehen somit für alle Sprachen (einschließlich VB und C#) zur Verfügung, die dieses Konzept unterstützen.

Ein anderes Beispiel für den sinnvollen Einsatz von generischen Klassen ist die Klasse System.Collections.ArrayList. Die Auflistung ArrayList ist nicht zweckgebunden und ihre Größe wird dynamisch angepasst. Sie kann gewöhnliche .NET- oder benutzerdefinierte Objekte enthalten. Um das zu erreichen, werden alle Objekte von ArrayList als Basisobjekte behandelt. Problematischerweise können diesbezüglich keine Einschränkungen für ArrayList festgelegt werden. Wenn Sie beispielsweise ArrayList zum Speichern von Customer-Objekten verwenden möchten, können Sie nicht sicher sein, dass nicht durch fehlerhaften Code versehentlich Zeichenfolgen, Ganzzahlen oder andere Objekttypen eingefügt werden, die später Probleme verursachen. Aus diesem Grund erstellen Entwickler häufig eigene stark typisierte Auflistungsklassen. Die Klassenbibliothek von .NET enthält Dutzende solcher Klassen.

Mit generischen Klassen kann dieses Problem gelöst werden. Sie können beispielsweise mithilfe von generischen Klassen eine Klasse mit dem Schlüsselwort Of deklarieren, so dass Sie sämtliche Datentypen verwenden können:

Public Class GenericList(Of ItemType)
    ' (Code goes here)
End Class

In diesem Fall erstellen Sie die neue Klasse GenericList, die mit jedem Objekttyp umgehen kann. Der zu verwendende Typ muss jedoch vom Client festgelegt werden. In Ihrem Klassencode wird der Typ über ItemType referenziert. Natürlich ist ItemType kein wirklicher Datentyp, sondern ein Platzhalter für den Typ, den Sie bei der Erstellung eines GenericList-Objekts angeben. In Codebeispiel 2 wird der vollständige Code für eine typsichere ArrayList-Klasse gezeigt:

Codebeispiel 2: Eine typsichere Auflistung unter Verwendung einer generischen Klasse.

Public Class GenericList(Of ItemType)
    Inherits CollectionBase

    Public Function Add(ByVal value As ItemType) _
      As Integer
        Return List.Add(value)
    End Function

    Public Sub Remove(ByVal value As ItemType)
        List.Remove(value)
    End Sub

    Public ReadOnly Property Item( _
      ByVal index As Integer) As ItemType
        Get
            ' The appropriate item is retrieved from 
            ' the List object and explicitly cast to 
            ' the appropriate type, and then returned.
            Return CType(List.Item(index), ItemType)
        End Get
    End Property
End Class

Die Klasse GenericList schließt eine normale ArrayList-Klasse ein. Es werden jedoch die stark typisierten Methoden Add() und Remove() zur Verfügung gestellt, in denen der Platzhalter ItemType verwendet wird.

Im folgenden Beispiel wird gezeigt, wie Sie die Klasse GenericList verwenden können, um eine ArrayList-Auflistung zu erstellen, die nur Zeichenfolgen unterstützt:

' Create the GenericList instance, and 
' choose a type (in this case, string)
Dim List As New GenericList(Of String)

' Add two strings.
List.Add("blue")
List.Add("green")

' The next statement will fail because it has the 
' wrong type. There is no automatic way to convert 
' a Guid object to a string. In fact, this line 
' won't ever run, because the compiler notices the 
' problem and refuses to build the application.
List.Add(Guid.NewGuid())

Für die Parametrisierung der Klasse gibt es keine Begrenzung. Im GenericList-Beispiel ist nur ein Typparameter vorhanden. Sie können jedoch einfach eine Klasse erstellen, die mit zwei oder drei Objekttypen funktioniert und Ihnen ermöglicht, daraus generische Typen zu machen. Dazu trennen Sie die einzelnen Typen durch Kommas (in den runden Klammern am Anfang der Klassendeklaration).

Sehen Sie sich z. B. die folgende Klasse GenericHashTable an: Diese ermöglicht, den Datentyp (ItemType) für die zu speichernden Objekte und die Schlüssel zur Indizierung von Datentypen (KeyType) zu definieren.

Public Class GenericHashTable(Of ItemType, KeyType)
    Inherits DictionaryBase
    ' (Code goes here.)
End Class

Ein weiteres wichtiges Feature von generischen Klassen ist die Verwendung von Einschränkungen, mit denen zulässige Datentypen festgelegt werden können. Sie möchten beispielsweise eine Klasse erstellen, die jeden Datentyp unterstützt, der einer bestimmten Schnittstelle entspricht. Fügen Sie in diesem Fall nach der Deklaration des Platzhalters für den Typ das Schlüsselwort As gefolgt von der Basisklasse oder der erforderlichen Schnittstelle hinzu.

Im folgenden Beispiel ist in der Definition der GenericList-Klasse festgelegt, dass nur serialisierbare Objekte verwendet werden können. (Ein Grund für diesen Ansatz könnte sein, dass Sie der Klasse GenericList eine weitere Methode hinzufügen möchten, die Serialisierung erfordert, beispielsweise eine Methode, die alle Objekte in einen Stream schreibt.)

Public Class GenericList(Of ItemType As ISerializable)
    Inherits CollectionBase 
    ' (Code goes here.)
End Class

Sie können beliebig viele Einschränkungen festlegen, sofern Sie die Klassen oder Schnittstellen durch das Symbol "&" trennen. Einschränkungen werden vom Compiler durchgesetzt.

Übrigens sind sich die Entwickler von .NET Framework der Nützlichkeit generischer Auflistungen bewusst und haben daher schon einige erstellt, die Sie verwenden können. Sie finden diese im Namespace Systems.Collections.Generic. Dazu gehören:

  • List: Eine Basisauflistung wie im GenericList-Beispiel.

  • Dictionary: Eine Name/Wert-Auflistung, in der jedes Objekt über einen Schlüssel indiziert ist.

  • LinkedList: Eine verknüpfte Liste, in der jedes Objekt in der Kette auf das nachfolgende zeigt.

  • Queue: Eine FIFO-Auflistung (First-In-First-Out).

  • Stack: Eine LIFO-Auflistung (Last-In-First-Out).

  • ReadOnlyCollection: Eine Auflistung, bei der die Anzahl der Objekte bei der Erstellung festgelegt wird und nicht mehr geändert werden kann.

  • SortedDictionary: Eine Name/Wert-Auflistung, die immer sortiert vorliegt.

Die meisten dieser Typen bilden einen Typ aus dem Namespace System.Collections ab. Die alten Auflistungen bleiben aus Gründen der Abwärtskompatibilität erhalten.

Schlussbemerkung

In diesem Artikel wurde gezeigt, dass die Änderungen in der aktuellen Version von VB Verbesserungen darstellen, die Programmierern das Leben erleichtern, ohne dass vorhandener Code dadurch ausgedient hat. Bei vielen dieser Änderungen handelt es sich um kleinere Sprachfeatures, die aus C# importiert wurden (z. B. Operatorüberladung). Bei einigen Neuerungen handelt es sich jedoch um vollständig neue Features, die in der aktuellen Common Language Runtime implementiert sind (z. B. generische Klassen). Die Sprache VB ist lebendig und wird kontinuierlich weiterentwickelt, um Verbesserungen zu erreichen.

Weitere Informationen zu Hardcore Visual Studio und Pinnacle Publishing finden Sie auf der Website http://www.pinpub.com/ (in Englisch).