(0) exportieren Drucken
Alle erweitern
Erweitern Minimieren

OOP – VB(A) unter .NET

Veröffentlicht: 16. Sep 2001 | Aktualisiert: 18. Jun 2004

VB.NET ist ernsthaft objektorientiert und die voraussichtlich übernächste Version von VBA wird es auch sein. In einem Atemzug mit OOP wird auch immer von Vererbung gesprochen. Ein Beispiel zeigt, wie Sie Vererbung in VB.NET nutzen, wie die neue Syntax aussieht und welche Vorteile das neue Typmodell bringt.

Auf dieser Seite

 Konstruktoren
 Neue Syntax für Eigenschaften
 Erste Ableitungen
 Instanzierbare Klassen
 Objekthierarchien unter der Lupe
 Besonderheiten

Diesen Artikel können Sie hier lesen dank freundlicher Unterstützung der Zeitschrift:

Haben Sie sich schon einmal mit dem Objektmodell von Outlook beschäftigt? Es enthält unter anderem Objekte für Mails (MailItem), Aufgaben (TaskItem) und Notizen (NoteItem). Obwohl die Objekte Gemeinsamkeiten haben, sind sie völlig unabhängig voneinander. COM (ActiveX) unterstützt nun mal keine Vererbung, und alle Outlook-Objekte sind COM-Objekte.

Listing 1: Die PI-Klassen

Imports System 
Imports System.Collections 
Imports System.Console 
Imports Microsoft.VisualBasic 
Namespace PI ' PI = Personal Information  
MustInherit Class PIItem 
Private strContent as String 
Private strSubject as String 
Private dateCreated, dateModified as Date 
Protected Shared NewLine As String = Chr(13) & Chr(10) 
Overloads Sub New() 
' System.Console.WriteLine("PIItem New 0") 
dateCreated = Now() 
dateModified = dateCreated 
End Sub 
Overloads Sub New(strSubject as String, strContent as String) 
Me.New() 
' System.Console.WriteLine("PIItem New 2") 
Me.strSubject=strSubject 
Me.strContent = strContent 
End Sub 
Public Property Content As String 
Get 
Content = strContent 
End Get 
Set 
strContent = value 
dateModified = Now() 
End Set 
End Property 
Public Property Subject As String 
Get 
Subject = strSubject 
End Get 
Set 
strSubject = value 
dateModified = Now() 
End Set 
End Property 
Public ReadOnly Property CreationDate As Date 
Get 
CreationDate = dateCreated 
End Get 
End Property 
Public ReadOnly Property LastModified As Date 
Get 
LastModified = dateModified 
End Get 
End Property 
MustOverride Public ReadOnly Property Description As String 
Overrides Public Function ToString() As String 
ToString = "*** " & strSubject & " ***" & NewLine & strContent & NewLine 
ToString &= ("Angelegt: " & dateCreated.ToString() & NewLine) 
ToString &= ("Letzte Aenderung: " & dateModified.ToString() & NewLine) 
End Function 
End Class 
MustInherit Class PIItemWA ' WA = with attachments 
Inherits PIItem 
Protected atts as StringCollection 
Overloads Sub New() 
MyBase.New() 
End Sub 
Overloads Sub New(strSubject as String, strContent as String) 
MyBase.New(strSubject, strContent) 
End Sub 
Public Sub AddAttachment(strFilename as String) 
If atts is Nothing then 
atts = new StringCollection 
End if 
atts.Add(strFilename) 
End Sub 
Overrides Public Function ToString() As String 
Dim s As String 
ToString = MyBase.ToString() 
if Not (atts is Nothing) then 
ToString &= ("Anhaenge: ") 
For each s in atts 
ToString &= (s & ";") 
next 
ToString &= NewLine 
end if 
End Function 
End Class 
Class AdrCollection 
Inherits StringCollection 
Public Sub AddColl(sc As StringCollection) 
Dim s as String 
For each s in sc 
Me.Add(s) 
next 
End Sub 
End Class 
Class MailItem 
Inherits PIItemWA 
Private Shared User as String 
Protected strSender as String 
Protected Recipients, CC As AdrCollection 
Private dateSent as Date 
Private bSent as Boolean 
Shared Sub New() 
' System.Console.WriteLine("MailItem Shared New") 
User = "Mister Mail" 
End Sub 
Overloads Sub New() 
MyBase.New() 
strSender = User 
Recipients = New AdrCollection 
bSent=false 
End Sub 
Overloads Sub New(strSubject as String, strContent as String, strSender as String) 
MyBase.New(strSubject, strContent) 
Me.strSender = strSender 
Recipients = New AdrCollection 
bSent=false 
End Sub 
Overloads Public Sub AddRecipient(strRecipient as String) 
Recipients.Add(strRecipient) 
End Sub 
Overloads Public Sub AddRecipient(rs as StringCollection) 
Recipients.AddColl(rs) 
End Sub 
Public Sub AddCC(strCC as String) 
If CC is Nothing then 
CC = New AdrCollection 
End if 
CC.Add(strCC) 
End Sub 
Public ReadOnly Property Sender as String 
Get 
Sender = strSender 
End Get 
End Property 
Public Function Send() As Boolean 
If Recipients is Nothing then 
Send = false 
else 
' Send it 
dateSent = Now() 
bSent=true 
Send = true 
end if 
End Function 
Public ReadOnly Property SentOn as Date 
Get 
SentOn = dateSent 
End Get 
End Property 
Overrides Public ReadOnly Property Description As String 
Get 
Description = "E-Mail" 
End get 
End Property 
Overrides Public Function ToString() As String 
Dim s as String 
ToString = "MAIL" & NewLine & MyBase.ToString() 
ToString &= ("Absender: " & strSender & NewLine) 
if bSent then 
ToString &= ("Gesendet am: " & dateSent.ToString() & NewLine) 
else 
ToString &= "Noch nicht gesendet" & NewLine 
end if 
if Recipients.Count > 0 then 
ToString &= "Empfaenger: " 
For each s in Recipients 
ToString &= (s & ";") 
next 
end if 
if Not (CC is Nothing) then 
ToString &= "CC: " 
For each s in CC 
ToString &= (s & ";") 
next 
end if 
End Function 
End Class 
Class TaskItem 
Inherits PIItemWA 
Protected dateTask as Date 
Overloads Sub New() 
MyBase.New() 
End Sub 
Overloads Sub New(strSubject as String, strContent as String) 
MyBase.New(strSubject, strContent) 
End Sub 
Public Property DueDate as Date 
Get 
DueDate = dateTask 
End Get 
Set 
DateTask = value 
End Set 
End Property 
Overrides Public ReadOnly Property Description As String 
Get 
Description = "Aufgabe" 
End Get 
End Property 
Overrides Public Function ToString() As String 
ToString = "TASK" & NewLine & MyBase.ToString() 
ToString &= "Zu erledigen am: " & dateTask.ToString() & NewLine 
End Function 
End Class 
Enum NoteTypes 
PrivateNote 
BusinessNote 
CommonNode 
End Enum 
Class NoteItem 
Inherits PIItem 
Protected nt as NoteTypes 
Overloads Sub New(nt as NoteTypes) 
MyBase.New() 
Me.nt = nt 
End Sub 
Overloads Sub New(strSubject as String, strContent as String, nt as NoteTypes) 
MyBase.New(strSubject, strContent) 
Me.nt = nt 
End Sub 
Public Property NoteType as NoteTypes 
Get 
NoteType = nt 
End Get 
Set 
nt = value 
End Set 
End Property 
Overrides Public ReadOnly Property Description As String 
Get 
Description = "Notiz" 
End Get 
End Property 
Overrides Public Function ToString() As String 
ToString = "NOTE" & NewLine & MyBase.ToString() 
ToString &= System.Enum.GetName(nt.GetType(), nt) 
End Function 
End Class 
Public Class PIs 
shared Private Sub BaseClasses(o As Object) 
Dim t As Type 
t = o.GetType() 
System.Console.Write(t.Name) 
t = t.BaseType 
Do While Not (t is Nothing) 
System.Console.Write(".{0}", t.Name) 
t = t.BaseType 
Loop 
System.Console.WriteLine("") 
End Sub 
shared Sub Main() 
System.Console.WriteLine("PIs") 
Dim items as ArrayList = New ArrayList 
Dim mi as MailItem 
Dim ti as TaskItem 
Dim itm as PIItem 
Dim ni as NoteItem 
Dim sc As StringCollection = new StringCollection() 
sc.Add("clochmann@vba-magazin.de") 
sc.Add("aharnisch@vba-magazin.de") 
sc.Add("araum@vba-magazin.de") 
mi = New MailItem("Betreff 1", "Eine Mail", "ich") 
mi.Send 
items.Add(mi) 
mi = New MailItem("Betreff 2", "Eine 2te Mail", "ich") 
mi.AddRecipient("jemand@internet.de") 
mi.AddAttachment("file1.txt") 
items.Add(mi) 
mi = New MailItem() 
mi.Subject="A Subject" 
mi.Content="Inhalt" 
mi.AddRecipient(sc) 
items.Add(mi) 
ti = New TaskItem("Viel zu tun", "das und das und das und ...") 
items.Add(ti) 
ni = New NoteItem("Notiz", "Text text text", NoteTypes.PrivateNote) 
items.Add(ni) 
for each itm in items 
System.Console.WriteLine(itm.Description) 
System.Console.WriteLine(itm.ToString()) 
System.Console.WriteLine() 
next 
BaseClasses( mi ) 
BaseClasses( ti ) 
BaseClasses( ni ) 
Dim nt as NoteTypes 
BaseClasses( nt ) 
Dim i as Integer 
BaseClasses( i ) 
End Sub 
End Class 
End Namespace

Listing 1 zeigt eine beispielhafte Implementierung einiger Outlook- beziehnungsweise Personal-Information-Objekte in VB.NET, wobei deren Funktionalität nur angedeutet wird (es gibt zum Beispiel keinen Code, um Mails zu verschicken). Die drei zu entwerfenden Klassen sollen die in Tabelle 1 angegebenen Attribute haben, wobei Attribute der Oberbegriff für Methoden und Eigenschaften sind. Einige Attribute sind bei allen Klassen zu finden, andere tauchen hingegen nur bei ein oder zwei Klassen auf.

Tabelle 1: Die Attribute der drei zu implementierenden Klassen

Mail

Betreff, Inhalt (sonst auch Text oder Body genannt), Anlagedatum, Datum der letzten Änderung, Empfängerliste, CC-Liste (zusätzliche Empfänger), Liste mit Anhängen, Sendedatum

Aufgabe

Betreff, Inhalt, Anlagedatum, Datum der letzen Änderung, Liste mit Anhängen, Fälligkeitsdatum

Notiz

Betreff, Inhalt, Anlagedatum, Datum der letzen Änderung, Typ der Notiz (privat, geschäftlich, beides)

Die erste Klasse PIItem wird nicht durch ein Modul repräsentiert, sondern ein Schlüsselwort vergleichbar mit Type dient dazu, eigene Datenstrukturen zu definieren. Das hat den Vorteil, dass Sie in einer Datei mehrere Klassen definieren können.

In der Klasse werden einige Variablen deklariert. strSubject und strContent nehmen den Betreff und den Inhalt auf. dateCreated und dateModified speichern das Anlagedatum beziehungsweise das Datum der letzten Änderung (die Datumsangabe umfasst auch die Uhrzeit). Die Variablen sind private deklariert, können also nur innerhalb von PIItem verwendet werden.

Die Variable NewLine weist einige Besonderheiten auf. Shared bedeutet, dass sich alle Instanzen von PIItem dieselbe Variable teilen. Normalerweise verfügt jede Instanz einer Klasse über einen eigenen Satz von Mitgliedsvariablen. Jede Instanz von PIItem hat zum Beispiel eine eigene strSubject-Variable, sonst würden sich die Objekte ja nicht unterscheiden.

Protected bedeutet, dass die Variable innerhalb von PIItem und allen abgeleiteten Klassen benutzt werden kann, aber nicht von einem externen Aufrufer. Damit ist protected ein drittes Zugriffsattribut neben public und private. Außerdem wird die Variable bei der Deklaration initialisiert. Das ist eine Neuerung von VB.NET, die für alle Variablen gilt.

Konstruktoren

Auf die Variablendeklarationen folgen zwei Prozeduren mit dem Namen New. Eigentlich haben Prozeduren unterschiedliche Namen, die auch nicht dem Namen eines Operators gleichen dürfen. New dient, wie Sie weiter unten im Beispiel sehen, auch weiterhin zum Erzeugen von Objekten. New ist aber gleichzeitig der vorgegebene Name für den Konstruktor einer Klasse. Konstruktoren kennen Sie im Grunde schon, nur unter dem Namen Initialize. Der Konstruktor New ist aber kein Ereignis, sondern eine „normale" Sub-Prozedur, die von der Laufzeitumgebung aufgerufen wird.

Die beiden Prozeduren haben zwar den gleichen Namen, unterscheiden sich aber dadurch, dass die erste keine Parameter hat, die zweite jedoch zwei. Das genügt dem neuen Compiler, um sie zu unterscheiden, wenn sie als überladen gekennzeichnet sind (Overloads). Sie können nicht nur Konstruktoren überladen, sondern alle Methoden und Eigenschaften.

Konstruktoren können sich gegenseitig aufrufen, allerdings muss der Aufruf eines Konstruktors im Konstruktor immer die erste Anweisung sein. Die Datumswerte werden daher nur im ersten Konstruktor vorbelegt, der zweite Konstruktor ruft zu diesem Zweck den anderen Konstruktor auf. Ansonsten können Sie Konstruktoren nicht direkt aufgerufen, nur die Laufzeitumgebung ruft sie auf.

Die Parameter haben die gleichen Namen wie die Mitgliedsvariablen. Durch Voranstellen von Me identifizieren Sie die Mitgliedsvariable eindeutig.

Neue Syntax für Eigenschaften

Sehen Sie sich die Deklaration von Eigenschaften an, werden Sie feststellen, dass sich die Syntax geändert hat. Statt über zwei separate Routinen definiert zu werden, gibt es nur eine Prozedur mit bis zu zwei Anweisungsblöcken. Je nachdem, ob die Eigenschaft schreib- und lesbar ist oder nur eine Zuweisungsrichtung unterstützt, gibt es einen Set- beziehungsweise einen Get-Block. Content und Subject können gesetzt und gelesen werden, es gibt beide Blöcke. Die beiden Datumswerte können nur gelesen werden (sie sind als ReadOnly gekennzeichnet), weshalb es nur einen Get-Block gibt.

Es gibt noch eine fünfte Eigenschaft (Description), die weder einen Get- noch einen Set-Block hat, ja nicht einmal ein abschließendes End Property. Dafür ist sie als MustOverride gekennzeichnet. Das bedeutet, dass hier nur die Vorgabe gemacht wird, dass abgeleitete Klassen, die instanzierbar sein sollen, diese Eigenschaft implementieren müssen. Das ist vergleichbar mit der Definition einer Methode in einer Schnittstelle. Die Klasse, die die Schnittstelle implementiert, muss auch die Methode implementieren.

PIItem selbst überschreibt die Funktion ToString. Woher stammt diese Funktion? Ist PIItem nicht die grundlegende Basisklasse? Object ist nicht mehr nur der Variablentyp für COM-Objekte, sondern die Basisklasse überhaupt. Alle Klassen und Datentypen in .NET sind direkt oder indirekt von Object abgeleitet, Ihre eigenen Klassen ebenso. Object stellt Methoden und Eigenschaften bereit, die größtenteils überschreibbar sind. Eine dieser Methoden ist ToString, die dazu dient, eine textuelle Repräsentation des Objekts zurückzugeben. PIItem implementiert ToString so, dass die Funktion den Wert aller Mitgliedsvariablen ausgibt.
Die Klasse PIItem ist als MustInherit gekennzeichnet, das heißt, sie kann selbst nicht instanziert werden. Nur abgeleitete Klassen, die nicht selbst wieder MustInherit sind, können Objekte anlegen. PIItem hat zum einen nur eine abstrakte Eigenschaft, das Bilden einer Instanz ist schon aus diesem Grund nicht sinnvoll (und nicht möglich). Die Klasse ist zum anderen lediglich als Fundament vorgesehen und soll aus Designgründen nicht instanzierbar sein.

Erste Ableitungen

Da sowohl Mails als auch Aufgaben mit Anhängen versehen werden können, bietet es sich an, eine Klasse anzulegen, die diese Funktionalität zur Verfügung stellt, so dass MailItem und TaskItem sie via Vererbung nutzen und anbieten können.

Die Klasse PIItemWA ist von PIItem abgeleitet, was in VB.NET über die Inherits-Anweisung geschieht. PIItemWA verfügt somit über alle „Fähigkeiten" von PIItem, zum Beispiel die Eigenschaften Subject und Content. Zusätzlich stellt PIItemWA die Methode AddAttachment bereit, um Anhänge hinzuzufügen. Dazu wird der Dateiname angegeben, der intern in einer StringCollection, einem Collection-Typ des .NET-Frameworks, gespeichert wird. Sie ist im Kern vergleichbar mit dem Collection-Objekt von VBA, bietet aber mehr Möglichkeiten und ist speziell auf Strings ausgelegt. Das .NET-Framework stellt eine Reihe von Collection-Klassen zur Verfügung, zum Beispiel Stack, Queue oder Dictionary.

AddAttachment legt zusammen mit dem ersten Anhang eine Instanz dieser Collection-Klasse an, ohne Set zu verwenden. Es wird nicht mehr unterstützt. Der Hintergrund ist, dass es keine Standardeigenschaften mehr im bisherigen Sinn gibt.

PIItemWA implementiert wiederum zwei Konstruktoren, tut aber nichts weiter, als den jeweiligen Konstruktor der Basisklasse PIItem aufzurufen. MyBase verweist immer auf die Basisklasse (vergleichen Sie es im weitesten Sinn mit Me, das immer auf die aktuelle Instanz verweist). Mit MyBase.New() rufen Sie also den parameterlosen Konstruktor von PIItem auf. Konstruktoren werden nicht vererbt und Basiskonstruktoren werden nicht wie in anderen OOP-Sprachen automatisch aufgerufen.

Sie sehen hier eine weitere Neuigkeit von VB.NET: Bei Prozeduraufrufen müssen Sie immer die Klammern angeben, auch wenn es keine Parameter gibt und es sich um eine Sub handelt.

Laut Dokumentation muss der erste Aufruf in einem Konstruktor der Aufruf des Basiskonstruktors sein. In PIItem fehlt er, und trotzdem funktioniert alles tadellos. Das kann auf den Beta-Status, aber auch auf eine missverständliche Dokumentation zurückzuführen sein. Stellen Sie sich also darauf ein, dass sich bis zur Release-Version noch etwas tut. Allerdings dürfte es sich dabei nur um Kleinigkeiten handeln, da vieles schon sehr gut funktioniert.
PIItemWA überschreibt ToString und ergänzt die Funktionalität von PIItem, indem es die Anhänge ausgibt. Mit MyBase.ToString() rufen Sie die Funktion ToString von PIItem auf.

Die nächste Klasse aus Listing 1 ist AdrCollection, die von StringCollection abgeleitet wird. Das ist eine der gravierendsten Neuerungen des .NET-Frameworks gegenüber dem bisherigen COM-Bibliothekskonzept: Abgesehen von wenigen Ausnahmen sind alle Klassen erweiterbar (Schlüsselwort: NotInheritable). Da eine überschreibende Funktion die Arbeitsweise ihrer Basis auch einschränken kann, können Sie die Funktionalität des Frameworks in weitem Maße an Ihre Bedürfnisse anpassen.

In diesem Fall geht es darum, nicht nur einzelne Elemente, sondern eine bestehende StringCollection in eine neue Collection einzufügen. StringCollection bietet die Methoden Add und AddRange an, um einzelne Strings oder String-Arrays einzufügen, nicht jedoch eine Collection. AdrCollection stellt diese Funktion zur Verfügung.

Instanzierbare Klassen

Nun sind alle Vorbereitungen getroffen, um die PI-Klassen zu schreiben. MailItem wird von PIItemWa abgeleitet und verfügt damit über alle dort und in PIItem implementierten Attribute. MailItem selbst implementiert eine Sender-Eigenschaft (der Absender der Mail), zwei Empfängerlisten sowie das Sendedatum und ein Flag, ob die Mail gesendet wurde. Die Implementierung dieser Methoden und Eigenschaften bietet nichts grundlegend Neues. AddRecipient ist überladen Sie können einen String oder eine StringCollection als Parameter übergeben. Das Anlegen des AdrCollection-Objekts für Empfänger und CC-Empfänger ist zu Demonstrationszwecken unterschiedlich implementiert. Die Send-Methode ist nur ansatzweise implementiert, ein Sendevorgang findet nicht statt.

MailItem ist die erste Klasse, die Description implementiert. Es ist zugleich die erste Klasse, die instanzierbar ist. Bei PIItemWA wurde Description außer Acht gelassen die Klasse ist sowieso nicht instanzierbar, da sie mit MustInherit deklariert wurde, kann sie sich das erlauben. Würde MailItem Description nicht implementieren, würde der Compiler das nicht hinnehmen.

MailItem verfügt über die shared Variable User. Für gesendete Mails soll dort der aktuelle Benutzer stehen, der für alle Mails gleich ist. Daher wird eine Variable verwendet, die sich alle Instanzen teilen. User ist nur für MailItem sichtbar. Für empfangene Nachrichten wird der Absender über den Konstruktor mit drei Parametern festgelegt. Nun bleibt die Frage, wie der jeweilige Anwender festgestellt wird.

Eine mögliche Lösung ist die Verwendung einer shared Methode, die beim Programmstart aufgerufen wird. Sie dient zum Beispiel dazu, eine Datenbankverbindung aufzubauen, muss aber explizit aufgerufen werden – wer hat so etwas nicht schon einmal vergessen? Eine interessante Alternative ist ein shared Konstruktor, der von der Lauftzeitumgebung einmal aufgerufen wird. Das ist letztlich eine gemeinsame Methode, um deren Aufruf Sie sich nicht kümmern müssen – ideal also für Initialisierungen. In der Praxis würde dieser Konstruktor eine Funktion wie GetUserName aus dem Windows-API aufrufen, hier wird einfach ein Wert gesetzt.
TaskItem ist relativ einfach, die Klasse ist ebenfalls von PIItemWA abgeleitet und hat eine Eigenschaft, um festzuhalten, wann die Aufgabe zu erledigen ist. Ansonsten überschreibt sie Description und ToString.

NoteItem ist direkt von PIItem abgeleitet, da es für Notizen keine Anhänge geben soll. Die Klasse hat eine Eigenschaft, mit der Sie festlegen, ob die Notiz privat, geschäftlich oder beides ist. Für die drei Fälle wird eine Aufzählung (Enum) verwendet. Natürlich soll in ToString auch angegeben werden, um welchen Notiz-Typ es sich handelt, es wird also eine textuelle Wiedergabe des Wertes benötigt. In VBA 6 würden Sie ein Select Case oder die Bibliothek zum Auswerten von Typelibs verwenden. Mit .NET ist es ein Kinderspiel, die textuelle Wiedergabe eines Enum-Wertes zu erhalten. Alle Aufzählungen basieren auf der Klasse Enum aus dem .NET-Framework. Diese Klasse stellt die gemeinsame Methode GetName zur Verfügung, die eine Variable des entsprechenden Aufzählungstyps sowie eine Typinformation als Parameter erwartet. Diese liefert die Methode GetType, die unter .NET alle Objekte bereitstellen. Sie wird schon in Object vorgegeben und sollte von allen Klassen überschrieben werden. Sie müssen sich nicht darum kümmern, das übernimmt VB.NET für Sie.

In Outlook ist die Subject-Eigenschaft des Notiz-Objekts nur lesbar, weil die erste Zeile des Textes als Betreff interpretiert wird. Ließe sich das auch hier realisieren? Die VB.NET-Dokumentation erwähnt das Schlüsselwort Shadow, mit dem sich die bestehende Implementierung einer Methode in einer abgeleiteten Klasse ändern lässt. Auf diesem Weg könnte sich aus der Schreib-/Lese-Eigenschaft eventuell eine Nur-Lese-Eigenschaft machen. Shadow ist in der Beta 1 noch nicht realisiert. Außerdem ist ein solcher Schritt gut zu überlegen, denn Sie hebeln damit den polymorphen Charakter der Klassen aus. NoteItem passt damit nicht mehr zu dem durch PIItem vorgegebenen Muster, die Subject-Eigenschaft lässt sich nicht mehr durchgängig nutzen.

Nachdem die Klassen geschrieben sind, sollen sie auch benutzt werden. Da es in VB.NET keine „alleinstehenden" Funktionen mehr gibt, wird eine weitere Klasse (PIs) mit zwei Methoden angelegt. Die Hauptroutine Main ist der typische Einstiegspunkt in ein .NET-Programmm, in dem einige Instanzen erzeugt und in der Collection ArrayList gespeichert werden, einer dynamischen Liste mit Array-Eigenschaften. Nachdem alle Objekte angelegt sind, wird sie in einer For-Each-Schleife durchlaufen und für jedes Objekt werden Description und ToString aufgerufen.

Alle Ausgaben erfolgen auf der Konsole (Eingabeaufforderung). Dazu werden die Methoden WriteLine und Write aus der Klasse Console verwendet. Hier ein Ausschnitt aus der Ausgabe, die Sie in der Datei out.txt auf der Heft-CD finden:

E-Mail 
      MAIL 
      *** Betreff 2 *** 
      Eine 2te Mail 
      Angelegt: 2000-12-03T11:23:20 
      Letzte Aenderung: 2000-12-03T11:23:20 
      Anhaenge: file1.txt; 
      Absender: ich 
      Noch nicht gesendet 
      Empfaenger: jemand@internet.de;

Objekthierarchien unter der Lupe

Eine wirklich spannende Methode ist BaseClasses. Sie ermittelt zur Laufzeit die Klassenhierarchie (Bild 1), stellt also fest, von welchen Klassen zum Beispiel MailItem abgeleitet ist. Auch das ist unter .NET denkbar einfach. Wie schon bei der Aufzählung ermitteln Sie mit GetType die Typinformationen, die in der Klasse Type verwaltet werden. Bisher wurde die Klasse Type nicht direkt benutzt, sondern an GetName übergeben. Type stellt unter anderem die Eigenschaften Name und BaseType zur Verfügung. Name liefert den Namen eines Typs, BaseType die Typinformationen der Basisklasse oder Nothing, wenn es keine weitere Basisklasse gibt. Da die Ausgangsbasis immer Object ist, könnten Sie auch das als Endekriterium verwenden. Über BaseType können Sie in einer Schleife nach und nach alle Basisklassen ermitteln. Für die instanzierbaren PI-Klassen gibt BaseClasses Folgendes aus:

MailItem.PIItemWA.PIItem.Object 
TaskItem.PIItemWA.PIItem.Object
NoteItem.PIItem.Object


Interessant sind auch die Ausgaben für NoteTypes und Integer:

NoteTypes.Enum.ValueType.ObjectInt32.ValueType.Object

Listing 2: Die Steuerungsdatei für den Visual-Basic-Compiler

/main:PI.Pis
/r:System.dll
/r:Microsoft.Win32.Interop.dll
/r:Microsoft.VisualBasic.Compatibility.dll
/r:Microsoft.VisualBasic.dll
/t:Exe
/out:PI.exe


Die Vereinheitlichung des Typsystems betrifft auch einfach Datentypen wie Integer, die jetzt alle indirekt von Object abstammen.

Besonderheiten

Alle Klassen liegen in einem Namensraum, der durch Namespace festgelegt wird. Er ist ein zusätzliches Organisationssystem und kann mehrere Dateien umfassen. Die Klasse Class1 im Namensraum N1 ist völlig unabhängig von der Klasse Class1 im Namensraum N2.

Um das Beispiel auszuprobieren, genügt die Beta 1 des .NET SDKs, die Visual-Studio.NET-Beta müssen Sie nicht installieren. Zum SDK gehört der Visual-Basic-Compiler, mit dem Sie den Code aus Listing 1 kompilieren können. Verwenden Sie dazu Listing 2 beziehungsweise die Datei pi.vbc auf der Heft-CD sowie folgenden Aufruf auf der Kommandozeile:
vbc@pi.vbc
Dazu müssen Sie sich in dem Verzeichnis befinden, in dem die vb-Datei und die vbc-Datei liegen. Sie sollten dann die ausführbare Datei pi.exe vorfinden und starten können.

Tabelle 2: Neue und geänderte Schlüsselwörter in VB.NET

Class

Eine Klasse wird nicht mehr über ein Modul definiert, sondern wie in anderen Spachen über ein Schlüsselwort. Class leitet eine Klassendefinition ein, End Class schließt sie ab. Sie können mehrere Klassen in einer Datei definieren.

Inherits

Erweitert eine Klasse eine bestehende Klasse, legen Sie mit Inherits die zu erweiternde Klasse fest.
MustInherit Enthält eine Klasse nur grundlegende Elemente, so dass es nicht sinnvoll ist, Instanzen anzulegen, wird sie als MustInherit gekennzeichnet. Der Compiler verhindert dann, dass Instanzen erzeugt werden; die Klasse gilt als abstrakte Basisklasse.

NotInheritable, Overridable, Overrides, NotOverridable, MustOverride

Vererbung bedeutet nicht nur Wiederverwendung von Code, sondern auch die Möglichkeit, Methoden in einer abgeleiteten Klasse neu zu implementieren und so die Funktionalität zu erweitern beziehungsweise einzuschränken. Overridable kennzeichnet eine Methode als überschreibbar, also als nicht endgültig implementiert. In einer abgeleiteten KLasse kann die Methode neu implementiert werden und muss dort mit Overrides gekennzeichnet sein. NotOverridable definiert eine Methode als endgültig. MustOverride legt fest, dass die Methode in abgeleiteten Klassen überschrieben werden muss.

MyBase

Möchten Sie in einer überschriebenen Methode die entsprechende Methode der Basisklasse aufrufen, verwenden Sie MyBase, um den Bezug herzustellen. Die Verwendung ist ähnlich zu Me, womit Sie das aktuelle Objekt referenzieren.

Interface

Schnittstellen werden nun über ein Schlüsselwort und nicht mehr über ein Modul definiert. Sie schreiben keine leeren Methodenrümpfe, sondern nur noch den Methodenkopf.

Implements

Eine Klasse gibt über das Schlüsselwort Implements an, dass sie eine Schnittstelle implementiert. Sie muss alle Methoden dieser Schnittstelle implementieren, allerdings kann eine Methode unter einem anderen Namen implementiert werden als in der Schnittstellendefinition. Welche Methode eine Prozedur implementiert, gibt sie auch über das Schlüsselwort Implements an.

New

Das Schlüsselwort New dient als Operator zum Anlegen neuer Objekte und als Name für den Konstruktor einer Klasse. Der Konstruktor entspricht der Initialize-Methode im Klassenmodell von VBA. Jede Klasse kann mehrere Konstruktoren haben, die sich nur durch die Anzahl und die Typen der Parameter unterscheiden müssen.

Overloads

Eine Klasse kann mehrere Methoden mit dem gleichen Namen enthalten, die sich durch die Anzahl und die Typen ihrer Parameter unterscheiden. Zusätzlich müssen sie mit Overloads als überladen gekennzeichnet werden.

Protected

Neben Private und Public gibt es nun einen weiteren Zugriffsbegrenzer. Auf Protected-Attribute dürfen nur abgeleitete Klassen zugreifen. Sie sind nicht öffentlich, aber trotzdem außerhalb der Klasse verwendbar.

Shared

Über Shared legen Sie fest, dass alle Instanzen einer Klasse sich eine Variable oder Methode teilen, diese also nicht instanz-spezifisch sind.


Anzeigen:
© 2014 Microsoft