2 Objekte und Klassen in VB.NET
2.1.1 Objekt
Definition
|
Objekt
|
Ein Objekt steht für ein konkretes Ding (z.B. Der rote
Ferrari von Fred Vollgas). In C# sind sind Objekte Bündel
aus speziellen Daten und Prozeduren, die über eine
gemeinsamme Hauptspeicherreferenz erreichbar sind (z.B.
FredsFerrari.Farbe oder FredsFerrari.gasGeben(100);)
In der objektorientierten Sichtweise werden die Prozeduren eines
Objektes als Methoden, und die Daten als Elemente bezeichnet.
|
Durch die Einführung
des Objektbegriffes in C# können Systeme mit komplexer innerer
Struktur direkt beschrieben werden. Jedes Objekt wird mit einem Namen
gekennzeichnet, jeder Prozess in einem Objekt durch eine sogenannte
Methode ausgedrückt, und jeder Zustand durch eine
Eigenschaft dokumentiert. Beziehungen und Prozesse, an denen
mehrere Objekte beteiligt sind, können durch Methoden, die
Objekte als Parameter erwarten, und Eigenschaften, die wiederum
Objekte sind, ausgedrückt werden.
2.1.2 Objektdiagramm
2.1.3 Beispiel
für Objekt: Dateisystem
Aufgaben:
Beschreiben Sie
folgende Systeme durch Objektmengen. Stellen Sie die Objekte durch
Objektdiagramme dar.
Bankkonto
Geometrische
Figuren
2.2 Klassen und Vererbung
Definition
|
Klasse
|
Eine Klasse ist eine Menge von Objekten, die
einen gemeinsammen strukturellen Aufbau aus Daten und Prozeduren
haben. Die Menge kann durch eine Klassendeklaration beschrieben
werden. Eine Klassendeklaration listet Deklarationen von
Datenelementen und Prozeduren auf, die die Objekte der Klasse
enthalten.
|
2.2.1 Klassendeklaration
In VB.NET werden
Klassen durch Klassenblöcke deklariert
Class NameDerKlasse
' Deklaration und Definition der Member
End Class
2.2.2 Lebenszyklus eines Objektes
2.2.3 Konstruktor
Definition
|
Konstruktoren
|
Sind vom Anwender überschreibbare Prozeduren, die
unmittelbar nach Allokation des Objektes der Klasse auf dem Heap
gestartet werden. Konstruktoren können
wie normale Prozeduren Eingaben verarbeiten, jedoch können
sie keine Ausgaben vornehmen !
In VB.NET werden Konstruktoren in Methoden
mit dem Namen New(...) implementiert. New kann
mehrfach überladen sein.
Class Lager
public shared instancecounter as Integer = 0
// Konstruktor
public Sub New(pKapzitaet as Integer)
instancecounter += 1
End Sub
:
End Class
|
2.2.3.1 Statische Konstruktoren
Um statische
Klassenkomponenten zu initialisieren gibt es spezielle Konstruktoren,
genannt statische Konstruktoren. Diese werden beim erstmaligen
gebrauch einer Klasse aufgerufen:
class C {
public static int anz_instanzen;
static C() {
anz_instanzen = 1;
}
}
2.2.3.2 Objektinitialisierer (ab .NET 3.5)
Das Implementieren
von Konstruktoren, die alle möglichen Einsatzszenarien abdecken,
ist häufig zeitraubende Routinearbeit. Ab .NET 3.5 bieten sich
als bequeme Alternative Objektinitialiserer an. Hierbei kann eine in
geschweiften Klammern gefasste Initialisierungsliste für
Eigenschaften und Felder dem Konstruktor einer Klasse übergeben
werden. Reihenfolge und Vollständigkeit spielen dabei keine
Rolle.
Beispiel:
Die folgende Klasse
verzichtet auf explizite Konstruktoren.
Class Filedesccriptor
Public filename as String
Public filetype as String
Public sizeInBytes as Integer
End Class
Stattdessen
instanziiert der Anwender, indem dem Konstruktor eine für den
Anwendungsfall spezifische Initialisierungsliste übergeben wird.
' Klassische Initialisierung
Dim fd as Filedesccriptor = new Filedesccriptor
fd.filename = "C:\boot.ini"
'...
' Neu: Objektinitialisierer anstelle Konstruktors
Dim fd2 as New Filedesccriptor With { .filename = "boot.ini", _
.filetype = ".ini", _
.sizeInBytes = 999 };
2.2.3.3 Anonyme Typen (ab .NET 3.5)
Mit der Einführung
von Linq ab .NET 3.5 wurden auch das Feature der anonyme Typen
erforderlich. Das Ergebnis einer Linq- Abfrage muss wg. der strengen
Typisierung in .NET einen Typen haben, der der Struktur des
Ergebnisses entspricht. Da der Compiler aus der Linq- Abfrage die
Typdeklaration selbständig ableiten kann, haben die VB.NET
Entwickler mit den anonymen Typen den Programmiere von der Pflicht
entbunden, für jede Linq- Abfrage eine Typdeklaration für
das Ergebnis anzufertigen.
' Anonyme Typen
var fdAnonym = New With{ filename = "boot.ini", filetype = ".ini", sizeInBytes = 999 }
' Auch für anonyme Typen gelten strenge Typisierung
fdAnonym.sizeInBytes = "Hallo Welt" ' Fehler
2.2.4 Destruktor und Dispose
Definition
|
Destruktoren
|
Spezielle Funktionen einer Klasse, die immer unmitterlbar vor dem
Löschen eines Objektes durch den GC starten. Entspricht der
Finalize – Methode von System.Object.
|
Definition
|
Dispose- Methode
|
Jede Klasse kann die Schnittstelle IDisposable implementieren,
welche die Methode Dispose() deklariert. Dispose wird in
einer Klasse implementiert, um sofort Resourcen freizugeben, wenn
das Objekt nicht mehr benötigt wird.
Hat die Dispose- Methode bereits alle Aufräumarbeiten
erledigt, dann kann der explizite Aufruf des Destruktors durch
den GC unterdrückt werden wie folgt:
GC.SuppressFinalize(Me);
|
2.2.5 Shared Member
Es gibt Methoden und
Membervariablen, die nicht an eine spezielle Instanz gebunden sind.
Beispielsweise kann eine Klasse SVal zur Darstellung von
Wegmaßen eine Methode zur Umrechnung von einem Wegmaß in
ein anders wie folgt enthalten:
' Klase zur Darstellung von Wegmaßen
Class SVal
Public value As Double
Public unit As SUnits
Public Function from_to(ByVal fromUnit As Sunits,
ByVal toUnit As Sunits,_
ByVal value As Double) As Double
:
End Class
Die Funktion gehört zum Kontext
Wegmaß, jedoch wäre eine konkrete Bindung an ein Wegmaß-
Objekt sinnlos. Deshalb kann sie als shared Member mittels des
Zugriffsmodifizierers Shared deklariert werden und kann
schließlich über den Klassennamen aufgerufen werden:
' Klase zur Darstellung von Wegmaßen
Class SVal
Public value As Double
Public unit As SUnits
' Folgende Funktion ist an keine Instanz (Wegmaß) gebunden.
' Mit ihr können Wegwerte von einer Einheit in eine andere
' umgerechnet werden.
Public Shared Function from_to(ByVal fromUnit As Sunits,_
ByVal toUnit As Sunits,_
ByVal value As Double) As Double
:
End Class
Sub Main()
:
Dim weg_in_km as Double = SVal.from_to(SUnits.s_mm, SUnits.s_km, 99)
:
End Sub
2.2.6 Eigenschaften
Eigenschaften sind
Objektzustände, deren Zugriff über Get/Set Methoden
gesteuert wird.
Class CConnectionString
Dim Server as String
Dim Database as String
:
public Property conString as String
Get
return "Server=" + Host + ";" + "Database=" + Database
End Get
Set(ByVal Value as String)
' String in die Bestandteile aufsplitten und Werte den
' Membervariablen zuweisen
End Set
End Property
End Class
2.2.7 Events und Delegates
2.2.7.1 Klasse mit Events definieren
Als Beispiel wird
eine Klasse aufgeführt, die einen Hub für Fehler und
Statusmeldungen in Anwendungen anbietet. An die Events EventError,
EventMsg und EventStatus
können beliebige
Eventhandler zur Verarbeitung und Präsentation der
entsprechenden Klasse von Meldungen registriert werden. Gefeuert
werden die Events aus der Anwendung mittels der Methoden LogError
etc..
<Serializable()> _
Public Class CLogVb
' Ereignisse für Fehler und Nachrichten
Public Delegate Sub DGLog(ByVal no As Integer, ByVal msg As String)
' Ereignis, an das Abonnenten Routinen zur Protokollierung und Darstellung von
' Fehlermeldungen binden können
Public Event EventError As DGLog
' Allgemeine Methode, über die Protokollierung und Darstellung von
' Fehlermeldungen angestoßen wird
Public Sub LogError(ByVal errno As Integer, ByVal msg As String)
SyncLock Me
RaiseEvent EventError(errno, msg)
End SyncLock
End Sub
' Ereignis, an das Abonnenten Routinen zur Protokollierung und Darstellung von
' allgemeinen Meldungen binden können
Public Event EventMsg As DGLog
' Allgemeine Methode, über die Protokollierung und Darstellung von
' allg. Meldungen angestoßen wird
Public Sub LogMsg(ByVal msgno As Integer, ByVal msg As String)
SyncLock Me
RaiseEvent EventMsg(msgno, msg)
End SyncLock
End Sub
' 15.9.2005, mko
' Ereignis, an das Abonnenten Routinen zur Protokollierung und Darstellung von
' allgemeinen Meldungen binden können
Public Event EventStatus As DGLog
' Allgemeine Methode, über die Protokollierung und Darstellung von
' Programmzuständen angestoßen wird
Public Sub LogStatus(ByVal statusno As Integer, ByVal status As String)
SyncLock Me
RaiseEvent EventStatus(statusno, status)
End SyncLock
End Sub
' Registrieren eines Objektes mit Routinen zur Behandlung von Ereignissen
' (Eventhandler)
Public Sub registerLogHnd(ByVal iLogHnd As ILogHndVb)
AddHandler EventError, AddressOf iLogHnd.OnError
AddHandler EventMsg, AddressOf iLogHnd.OnMsg
AddHandler EventStatus, AddressOf iLogHnd.OnStatus
End Sub
' Deregistrieren eines Objektes mit Routinen zur Behandlung von Ereignissen
' (Eventhandler)
Public Sub deregisterLogHnd(ByVal iLogHnd As ILogHndVb)
RemoveHandler EventError, AddressOf iLogHnd.OnError
RemoveHandler EventMsg, AddressOf iLogHnd.OnMsg
RemoveHandler EventStatus, AddressOf iLogHnd.OnStatus
End Sub
End Class
2.2.7.2 Eventhandler zuweisen
Die Registrierrung
von Eventhandlern erfolgt in VB.NET mittels AddHandler:
Module Module1
Sub MeldeFehler(ByVal nr As Integer, ByVal meldung As String)
Debug.WriteLine("Err: " & nr & ", " & meldung)
End Sub
Sub MeldeFehler2(ByVal nr As Integer, ByVal meldung As String)
Debug.WriteLine("Err++: " & nr & ", " & meldung)
End Sub
Sub MeldeInfo(ByVal nr As Integer, ByVal meldung As String)
Debug.WriteLine("Msg: " & nr & ", " & meldung)
End Sub
Sub Main()
Dim log As New mko.CLogVb
' Registrieren der Eventhandler im Objekt log
AddHandler log.EventError, AddressOf MeldeFehler
AddHandler log.EventError, AddressOf MeldeFehler2
AddHandler log.EventMsg, AddressOf MeldeInfo
log.LogError(99, "Eine Fehlermeldung")
log.LogMsg(100, "Eine Infomeldung")
End Sub
End Module
2.2.7.3 Delegates- Verwaltungsklassen für Einsprungadressen
Die Events sind vom
Typ Delegates. Das sind Klassen, die der Kompiler automatisch aus
einer Delegate- Deklaration von der Basisklasse System.Delegate
ableitet. Diese verwalten
Einsprungadressen für Methoden, deren Typ durch den Rückgabetyp
und die Parameterliste gekennzeichnet ist.
Module Module1
Sub Worker(ByVal auftrag As Integer, ByVal symbol As String)
For i As Integer = 0 To auftrag
Debug.Write(symbol)
System.Threading.Thread.Sleep(500)
Next
End Sub
' VB- Compiler erzeugt gem. folgender Anweisung eine Klasse, die Einsprungadressen vom
' Typ Worker verwalten kann
Delegate Sub DGWorker(ByVal auftrag As Integer, ByVal symbol As String)
Sub Main()
Debug.WriteLine("Erster Auftrag")
Worker(3, ".")
Debug.WriteLine("Zweiter Auftrag")
Dim dg As New DGWorker(AddressOf Worker)
dg.Invoke(3, "2")
Debug.WriteLine("Auftrag 3 und 4 parallel starten")
Dim ares As IAsyncResult = dg.BeginInvoke(20, "4", Nothing, Nothing)
dg.Invoke(10, "3")
'ares.AsyncWaitHandle.WaitOne()
dg.EndInvoke(ares)
End Sub
End Module
2.2.7.4 Lambda- Ausdrücke
Bisher
wurde davon ausgegangen, daß einem Delegate eine gewöhnliche
sog. benannte Methode zugewiesen wird. In Fällen, wo ein Stück
ausführbarer Kode nur an einer Stelle im Programm zugewiesen
werden muß, kann der Overhead einer kompletten
Methodendeklaration durch sog. Lambda- Ausdruck eingespart werden.
Delegate Sub DGWorker(ByVal auftrag As Integer, ByVal symbol As String)
...
Dim dg As New DGWorker(AddressOf Worker)
' Dem Delegate wird ein Lambda- Ausdruck zugewiesen
dg = Sub(auftrag As Integer, symbol As String)
For i As Integer = 0 To auftrag
Debug.Write(symbol)
System.Threading.Thread.Sleep(500)
Next
End Sub
dg.Invoke(3, "2")
Weitere Beispiele für
Lambda- Ausdrücke:
2.2.7.4.1 Einfache Lambdaausdrücke
Im Folgenden wird in einem VB- Unterprogramm ein
Lambdaausdruck gebildet. Anschliesend wird er mit speziellen
Parametern evaluiert.
' Hier wird der Typ von op mittels Typinferenz bestimmt. Der zugewiesene Lambda- Ausdruck
' erfordert dabei Delegate mit
' ACHTUNG: Funktionniert nur bein OPTION INFER ON !
Dim op = Function(a As Int32, b As Int32, c As Int32) As Int32
Return a * (b + c)
End Function
Debug.WriteLine("2*(3+5) = " & op(2, 3, 5))
2.2.7.4.2 Lambdaausdrücke in Listenoperationen
Im Folgenden wird ein Lambdaausdruck auf alle
Elemente in einer Liste angewendet. Das Ergebniss ist eine Liste mit
den Quadraten der ursprünglichen Listenelemente.
' Lambda- Ausdruck auf Listen anwenden
Dim prim() As Integer = {2, 3, 5, 7, 11, 13, 17, 19, 23}
Dim prim2 As New List(Of Integer)
Array.ForEach(prim, Sub(p)
prim2.Add(p * p)
End Sub)
2.2.8 Konstanten und Readonly- Member
Konstanten
sind Felder, deren Wert zur Kompilationszeit definiert wird, und die
anschließend nur über den Klassennamen referenzierbar
sind.
const e as Double = 2.72;
Readonly- Member sind Felder, deren Wert zur Konstruktionszeit
definiert werden. D.h. ihnen können im Konstruktor Werte
zugewiesen werden. Zu späteren Zeitpunkten ist keine Zuweisung
mehr möglich.
class Figur
ReadOnly max_anz_leben as Integer
Public Sub New(max_al as Integer)
max_anz_leben = max_al
End Sub
Public Sub ueberleben()
max_anz_leben += 1 ' Fehler, da readonly
End Sub
:
End Class
2.3 Vererbung
Bei der
objektorientierten Programmierung fällt auf, das verschiedene
Klassendekalrationen in einem Projekt Abschnitte mit identischen
Deklarationen von Eigenschaften und Methoden enthalten können.
Hier kann es sinvoll sein, diese Gemeinsamkeiten zentral an einer
Stelle im Programm zu deklarieren zwecks Erhöhung der
Übersichtlichkeit und Vereinfachung der Wartung.
Ein anderer Aspekt
ist die Verwaltung von Objekten unterschiedlicher Typen in einer
Liste wie z.B. bei der programmtechnischen Darstellung von CAD-
Zeichnungen (Menge aus Linen, Kreisen etc). Ein Ausdruck der
Zeichnung wird durch einen Durchlauf der Liste realisiert, wobei von
jedem Objekt die draw- Methode aufgerufen wird.
2.3.1 Definition
von Vererbungsbeziehungen
2.3.1.1 Beispiel: Entwickeln einer Klassenbibliothek zur
Bearbeitung von technischen 2D- Zeichnungen
Technische 2D
Zeichungen sind aus elementaren geometrischen Primitiven wie Linien,
Rechtecke, Kreise, Ellipsen, Splines etc.. Es bietet sich in bietet
sich an, den Entwurf damit zu beginnen, für jedes Primitiv eine
Klasse zu deklarieren:
2.3.1.1.1 Klassen der Grafikprimitive
Wie
aus dem Diagramm ersichtlich, haben alle Klassen einen Satz
gemeinsamer Eigenschaften und Methoden:
Color,
zur Darstellung der Linienfarbe
style,
zur Darstellung der Strichart
unit, zur
Darstellung der Einheit, in der gezeichnet wird
Methode draw
zum Zeichnen der Figur auf einem Ausgabemedium
Methoden
translate, rotate und scale zum Verschieben, Drehen
und Strecken der Figur
Die Eigenschaften
color, style und unit sind in allen Klassen die
gleiche. Sie können in einer gemeinsammen Basisklasse aller
Primitivklassen zentral deklariert werden. Nennen wir diese
Klasse CFigur. Durch Vererbung werden die von CFigur
abgeleiteten Klassen mit den Eigenschaften von CFigur ausgestattet:
2.3.1.1.2 Klassenhierarchie CFigur
Die
Daklaratioen der Methoden draw, translate, rotate und scale
können nicht einfach in die Basisklasse CFigur verschoben
werden. Denn für jedes Klasse zu einem Grafikprimitv ist eine
individuelle Implentierung diesser notwendig.
Die Vererbung wird in
der Abgeleiteten Klasse deklariert mittels des Schlüsselwortes
Inherits:
Public Class CLinie
Inherits CFigur
:
End Class
2.3.2 Auflösen von Namenskonflikten bei der Vererbung
Bei der Vererbung
kann es schnell zu Namenskonflikten kommen. Beispielsweise
implementieren CLinie und CFigur jeweils einen Konstruktor New().
Zur korrekten Instanziierung eines CLinie- Objektes ist es notwendig,
daß auch der Konstruktor der Basisklasse CFigur aufgerufen
wird. Hier ist eine Unterscheidung im Kontext der abgeleiteten Klasse
zwischen eigenen Membern und der der Basisklasse nötig. Dies
geschieht durch das Schlüsselwort MyBase
Public Class CLinie
Inherits CFigur
:
Public Sub New()
MyBase.New() ' Aufruf des Konstruktors aus CFigur
End Sub
:
End Class
2.3.2.1 Überschatten von Membern aus der Basisklasse
Manchmal ist es
notwendig, den Typ einer Eigenschaft oder Methode in einer
abgeleiteten Klasse neu zu definieren. Dies geschieht durch
Überschatten (engl,. Shadowing) und wird in VB.NET durch
Schlüsselwort Shadows gekennzeichnet:
Class CFestung
Public mAlter As Int32
Public Sub setAlter(ByVal alter_neu As Double)
mAlter = CType(alter_neu, Int32)
End Sub
End Class
Class CBurg
Inherits CFestung
Shadows mAlter As Double
End Class
2.3.2.2 Überladen von Eigenschaften und Methoden
In der
Klassenbibliothek für 2D- Zeichnungen wurde für jedes
Primitiv ein Satz von Transformationsfunktionen definiert (translate,
rotate, scale). Nehmen wir die Translationsfunktion. Sie könnte
zu. Beispiel wie folgt definiert werden:
Sub translate(tx as Single, ty as Single)
Anstelle von tx und ty könnte aber
auch ein Punkt übergeben werden, der das Ende des
Verschiebevektors kennzeichnet:
Sub translate(vec as SPoint)
Um die erste, als such zweite Variante
zu ermöglichen, muß das Schlüsselwort Overloads
eingesetzt werden (insbesondere bei Vererbung)
Overloads Sub translate(tx as Single, ty as Single)
Overloads Sub translate(vec as SPoint)
2.3.3 Das Kapselungsprinzip
Bei der Entwicklung
großer Programmpakete hat es sich als sinvoll erwiesen,
Implementierungsdetails von Bibliotheken vor dem Anwender zu
verbergen. In VB.NET wird dieses sog. Kapselungsprinzip durch
Zugriffmodifikatoren für Klassenmember und Schnittstellen
realisiert.
2.3.3.1 Zugriffsmodifikatoren für die Kapselung
Zugriffsmodifikator
|
Beschreibung
|
Nicht deklarierebar in
|
Dim
|
nur im Block sichtbar, in dem deklariert wurde
|
|
Public
|
überall sichtbar. Über Public-
Methoden und Eigenschaften werden an die Objekte der Klasse
Nachrichten gesendet.
|
Prozeduren, Funktionen
|
Private
|
nur in der Klasse
sichtbar, in der Member deklariert wurde.
Zur Kapselung von Implementationsdetails in
einer Klasse
|
Prozeduren, Funktionen
|
Protected
|
nur von Membern
der eigenen oder von Membern in abgeleiteten Klassen sichtbar.
Zur Kapselung von Implementationsdetails in
einer Klassenhierarchie
|
Prozeduren, Funktione, Module
|
Friend
|
(analog internal
in C#) ist überall innerhalb der Assembly sichtbar.
Außerhalb der Assembly nicht sichtbar.
Zur Kapselung von Implementationsdetails in
einer Assembly
|
Prozeduren, Funktionen
|
2.3.3.2 Beispiel: Kapselung
Module Module1
Class CFestung
Public Shared mShared As Int16
Private mPrivat As Short
Protected mProtected As Int16
Friend mFriend As Int16
Public mPublic As Int16
Sub New(ByVal init As Short)
mShared = init
mPrivat = init + 1S
mProtected = init + 2S
mFriend = init + 3S
mPublic = init + 4S
End Sub
Public Sub tor_auf()
' Auf Private Elemente kann nur in Mathoden aus der Klasse
' selbst zugegriffen werden
mPrivat = 1000
End Sub
' Ein Ereignis deklarieren
Public Event treffer()
' Das Ereignis selbst auslösen
Public Sub getroffen()
RaiseEvent treffer()
End Sub
End Class
' Eine von Festung abgeleitete Klasse
Class CBurg
Inherits CFestung
' Konstruktoren werden nicht vererbt. Jede Klasse hat ihren
' eigenen Satz von Konstruktoren (Initialisierungsroutinen)
Sub New(ByVal init As Int16)
MyBase.New(init)
' Auf Protected- Member aus der Basisklasse kann in der abgeleiteten Klassen
' zugegriffen werden
mprotected *= 10S
End Sub
Function gebe_protected_aus() As Int16
Return mprotected
End Function
End Class
' Ein Eventhandler für Objekte vom Typ Festung
Sub festung_treffer()
Console.WriteLine("Festung wurde getroffen")
End Sub
Sub Main()
' Eisenstein ist ein Objekt vom Typ CFestung
Dim Eisenstein As New CFestung(10)
Dim Dreistein As New CFestung(100)
Dim Raubstein As New CBurg(1000)
Console.WriteLine("Zuegriff auf Protected {0}", Raubstein.gebe_protected_aus())
' Eventhandler registrieren
AddHandler Eisenstein.treffer, AddressOf festung_treffer
' Zugriff auf die Member
CFestung.mShared *= -1S
Eisenstein.mShared *= 99S
' Nur shared Elemente können dierekt über die Klasse aufgerufen
' werden. Es mus kein Objekt/Instanz existieren, um mit dem
' Element zu arbeiten
'CFestung.mPublic *= 12S
With Eisenstein
'.mPrivat *= -1
'.mProtected *= -1S
.mFriend *= -1S
.mPublic *= -1S
' Ereignis auslösen
.getroffen()
.tor_auf()
End With
Console.ReadLine()
End Sub
End Module
2.4 Polymorphismus
Definition
|
Polymorphe Operation
|
(Vielgestaltig) Sind Funktionen oder Prozeduren, die unter
gleichem Namen und mit gleicher Parameterliste in verschiedenen
Klassen deklariert, jedoch verschieden implementiert sind. Beim
Aufruf über ein Objekt wird immer die Implementierung aus
dem Typ des Objektes genommen. Erfolgt der Aufruf über eine
Referenz vom Typ einer Basisklasse, dann wird zur Laufzeit die
Implementierung über sog. virtuelle Funktionstabellen
bestimmt.
|
Beim
Instanziieren werden die vtabels so initilisiert, daß ihre
Einträge auf die korrekten Funktionen zeigen.
2.4.1.1 Beispiel
Im folgenden Beispiel
wird das erzeugen von Arbeitsfortschrittsmeldungen in der Methode
MakeProgressInfo gekapselt. Diese wird zu bestimmten
Zeitpunkten beim Scannen eines Verzeichnisses aufgerufen, um den
Client von DirTree über den aktuellen Arbeitsstand zu
informieren. In abgeleiteten Klassen können detailiertere
Informationen zum Arbeitsfortschritt benötigt werden. In diesem
Falle muß von der Klasse DirTreeProgressInfo eine
speziellere Arbeitsfortschrittmeldung abgeleitet werden. In einer
Methode, welche MakeProgressInfo überschreibt, muß die
abgeleitete Arbeitsfortschrittmeldung dann erzeugt werden.
Namespace DMS
Public Class DirTreeVb
'-----------------------------------------------------------------------------
' Member zur Ausgabe des Arbeitsfortschrittes
' Klasse mit Informationen über den Arbeitsfortschritt.
' Detailiertere Arbeitsfortschrittmeldungen müssen von dieser Klasse
' abgeleitet werden.
Public Class DirTreeProgressInfo
Inherits ProgressInfo
Public CountAllDirs As Integer
Public CountAllFiles As Integer
Public Sub DirTreeProgressInfo(ByVal CountAllDirs As Integer, ByVal CountAllFiles As Integer)
Me.CountAllDirs = CountAllDirs
Me.CountAllFiles = CountAllFiles
End Sub
End Class
' Funktionszeigertyp von Handlern zur Behandlung des Arbeitsfortschritts- Event
public delegate function DGEventProgress(DirTreeProgressInfo info) as Boolean
' Ereignis: Arbeitsfortschritt
Public Event EventProgress As DGEventProgress
' virtuelle Methode
' Generator für Arbeitsfortschrittmeldungen: Kann in abgeleiteten Klassen
' überschrieben werden, um detailiertere Arbeitsfortschrittmeldungen, die von
' DirTreeProgressInfo abgeleitet sind, zu erzeugen
Protected Overridable Function MakeProgressInfo() As DirTreeProgressInfo
return new DirTreeProgressInfo(m_dir_count, m_file_count);
End Function
End Class
End Namespace
2.5 Schnittstellen
Definition
einer Schnittstelle
Public Interface IPlotter
Sub print_line(ByVal a As SPoint, ByVal b As SPoint)
Sub print_circle(ByVal m As SPoint, ByVal radius As Double)
End Interface
Implementierung einer Schnittstelle
Public Class CDxfPlotter
Implements IPlotter
Public Sub print_line(ByVal a As SPoint, ByVal b As SPoint, ByVal style As CStyle)_
Implements IPlotter.print_line
:
End Sub
End Class
2.6 Fehlerbehandlung
Fehlerbehandlung
kann klassisch mittels dem Err Objekt (unstrukturiert)
bzw. modern mit dem try ... throw ... catch Block
erfolgen.
2.6.1 Fehlerobjekt auswerfen
Throw new Exception("Fehlermeldung");
2.6.2 Fehler behandeln
Try
' Programmcode, der Fehlerobjekte werfen kann
Catch ex As FileNotFoundException
' Behandeln einer Speziellen Ausnahme
Catch ex As Expception ex
' Behandeln einer allgemeinen Ausnahme
Finally
' Anweisungen, die in jedem Fall ausgeführt werden
End Try
2.6.3 Hierarchie der Ausnahmen
2.6.4 Beispiel
Try
Try
Throw new Exception("Ex Innen")
Catch ex As Exception
Console.WriteLine(ex.Message)
throw new Exception("Ex Catch")
finally
Console.WriteLine("Finally 2");
End Try
Console.WriteLine("Nach InnerTry");
Catch ex As Exception
Console.WriteLine(ex.Message);
finally
Console.WriteLine("Finally 1");
End Try
2.7 Attribute
In natürlichen
Sprachen werden mittels Attribute Eigenschaften von Substantiven
festgelegt wie heißer Tee oder grüne Farbe.
Analog werden durch Attribute in VB.NET zusätzliche
Informationen zu Klassen, Prozeduren und Variablen hinterlegt. Diese
Informationen können dann vom Compiler verarbeitet werden, oder
werden als Metadaten in der Assembly gespeichert.
Beispiel:
Definieren von
Metadaten ür die Assembly:
<Assembly: AssemblyTitle("GeoInfo")>
<Assembly: AssemblyDescription("Zugriff auf Datenbank")>
<Assembly: AssemblyCompany("mkoSoft")>
:
<Assembly: AssemblyVersion("1.0.*")>
2.7.1 Selbstdefinierte Attribute
Attribute sind
Klassen, die von System.Attribute abgeleitet sind. Jedes
Attribut ist selbst wieder mit dem Basisattribut AttributeUsage
ausgezeichnet. Damit ergibt sich folgende Grundstruktur für eine
Attributdeklaration:
<AttributeUsage(AttributeTargets.All)> Public Class CMyXAttribute
Inherits Attribute
Sub New(ByVal pName As String)
Name = pName
End Sub
Public Name As String
End Class
2.7.1.1 Selbstdefiniertes Attribut anwenden
Allgemein sind mit
Attributen beliebige Elemente in .NET wie Assembly, Klasse und Member
attributierbar. Über den Parameter AttributeTargets in
AttributeUsage kann die Menge der attributierbaren
Elemente eingeschränkt werden.
Die
Attributierung eines Elements erfolgt beispielsweise so:
<CMyX("Martin")> Public Class CTest
End Class
In der Parameterliste der Attributdefinition können Felder in
einer Kommaseparierten Liste dierekt Werte zugewiesen werden.
2.7.1.2 Attributeigenschaften auslesen
Die Klasse
System.Attribute stellt statische Methoden
Attribute.GetCustomAttribute(..) und
Attribute.GetCustomAttributes(...) bereit. Diese liefern eine
Referenz auf ein Attribut vom Typ object bzw. eine Referenz
auf ein Array mit Attributen zurück. Als Eingaben erwarten die
Funktionen das Type- Objekt der Instanz, deren Attribute ausgelesen
werden soll, sowie den Typ des auszulesenden Attributes.
Module Module1
Sub Main()
' Fall: Die Klasse Anwendung besitzt nur ein Attribut vom Typ MyAttribute
Dim myAtt As CMyXAttribute = CType(Attribute.GetCustomAttribute(GetType(CTest), GetType(CMyXAttribute)), _
CMyXAttribute)
If Not myAtt Is Nothing Then
Console.WriteLine("name= {0}", myAtt.name)
End If
End Sub
End Module
2.7.2