Inhaltsverzeichnis         

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.

  1. Bankkonto

  2. 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:

  1. Color, zur Darstellung der Linienfarbe

  2. style, zur Darstellung der Strichart

  3. unit, zur Darstellung der Einheit, in der gezeichnet wird

  4. Methode draw zum Zeichnen der Figur auf einem Ausgabemedium

  5. 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