© Martin Korneffel, Stuttgart 2003 +++ email: trac@n.zgs.de +++ web: www.s-line.de/homepages/trac

VB.NET

Inhalt

  1. Einführung

    1. Historische Entwicklung

    2. Ziel der Programmierung

    3. Grundprinzipien der Programmierung

      1. EVA- Prinzip

      2. Ereignisgesteuerte Programmierung

    4. IDE Visual Studio 2003

      1. Profile

      2. Projekte und Projektmappen

      3. Sichten auf den Code

      4. Einstellungen

      5. Aufgabenliste

      6. Steuerung der IDE über Kommandozeilen

      7. Dynamische Hilfe

    5. VB.NET Compiler

      1. Übersetzen auf der Kommandozeile

      2. Präprozessordirektiven

    6. Aufbau eines VB.NET Programmes

      1. Literale

      2. Operatoren

      3. Variablen

      4. Elementare Ein/Ausgabe

        1. Formatzeichenfolgen

        2. Formatzeichenfolgen für nummerische Typen

        3. Formatzeichenfolgen für Datumstypen

        4. Formatzeichenfolgen für Aufzählungstypen

        5. ToString und Formatierung

        6. Ausgabe mit IFormatProvidern

        7. Composit- Formating

      5. Enumerations

      6. Datenstrukturen

      7. Steuerung der Programmausführung

      8. Arrays

      9. Datum und Uhrzeit

      10. Strings

      11. Funktionen und Prozeduren

      12. Namespaces

    7. Objekte und Klassen in .NET

      1. Objekt

      2. Objektdiagramm

      3. Beispiel für Objekt: Dateisystem

    8. Klassen und Vererbung

      1. Klassendeklaration

      2. Lebenszyklus eines Objektes

      3. Konstruktor und Destruktor

      4. Das Kapselungsprinzip

      5. Shared Member

      6. Eigenschaften

      7. Events

      8. Konstanten und Readonly- Member

    9. Vererbung

      1. Definition von Vererbungsbeziehungen

      2. Auflösen von Namenskonflikten bei der Vererbung

        1. Überschatten von Membern aus der Basisklasse

        2. Überladen von Eigenschaften und Methoden

      3. Das Kapselungsprinzip

        1. Zugriffsmodifikatoren für die Kapselung

    10. Polymorphismus

    11. Schnittstellen

    12. Fehlerbehandlung

      1. Fehlerobjekt auswerfen

      2. Fehler behandeln

      3. Hierarchie der Ausnahmen

    13. .NET Datentypen

      1. Referenztypen vs Wertetypen

      2. Boxing und Unboxing- Konvertierung

      3. Typ bestimmen

      4. Implizite Typkonvertierung

      5. Explizite Typkonvertierung

      6. Reflektion

      7. Speziealwert Nothing

      8. Objektmodell von char

      9. Objektmodell von String

      10. Char , Strings und Unicode

    14. Collections

      1. IEnumerable und ICollection

      2. IList

      3. IDictionary

    15. Attribute

      1. Selbstdefinierte Attribute

    16. Serialisierung

Einführung

BASIC ist ein Akronym (Beginner’s All-purpose Symbolic Instruction Code = Allzweck-Symbolbefehlssprache für Anfänger) und bezeichnet eine Programmiersprache, die Mitte der 60-er von den US- Amerikanern John Kemeny und Thomas Kurtz entwickelt wurde. Sie diente ursprünglich für Schulungszwecke.

Ursprünglich war BASIC als Interpretersprache konzipiert. Ein geringer Umfang an Befehlen, die Insensitivität gegenüber der Groß/Kleinschreibung und die Interaktivität durch den Interpreter führten dazu, daß BASIC inbesondere unter Anfängern beliebt wurde.

Historische Entwicklung


Ziel der Programmierung

Standardsoftware anpassen

Beispiel: EXCEL wird als Kalkulationssoftware eingesetzt. Bestimmte Kalkulationen sollen online auf einem Webserver veröffentlicht werden, indem Inhalte aus Tabellenzellen in Datenbanktabellen auf dem Webserver übertragen werden. Für den Anwender soll die Übertragung genauso einfach wie ein Speichern des Arbeitsblattes sein. Als Werkzeug bietet sich hier VB und VBA an.

Automatisierung

Sich wiederholende, komplexe Arbeitsabläufe können in einem Script erfasst, und auf Knopfdruck gestartet werden. Beispiele: Backup von Datenbanken/Festplatten, Wiederherstellen von Arbeitsoberflächen (Anmeldescripte). Als Werkzeuge bieten sich hier Scriptsprachen wie PERL ound VBScript an.

Individualsoftware erstellen

Auf einer Plattform (PC oder Microcontroller) wird eine völlig neue Anwendung erstellt. Als Werkzeuge bieten sich hier Entwicklungsumgen wie Visual C++ oder Visual.NET an. Dies ist der kompliziteste Fall. Die Entwicklung von Individualsoftware kann sogar zur entwicklung völlig neuer Programmierwerkzeuge führen (UNIX-> C, DHTML-> JavaScript)

Grundprinzipien der Programmierung

EVA- Prinzip




Ereignisgesteuerte Programmierung

Die Welt besteht aus Objekten, die miteinander kommunizieren. Die Kommunikation erfolgt über Botschaften, die in den meisten objektoriantierten Sprachen als Methoden realisiert sind. Botschaften können Produkte von Ereignissen im System sein wie z.B. das Anklicken einer Schalftfläche durch einen Benutzer. Anderseits können Botschaften programmgesteuert an Objekte gesendet werden. Damit lassen sich Verarbeitungsformen wie Stapelverarbeitung (übergabe der Kontrolle an ein weiteres Objekt) und Client/Server (Ausfrufen eines Dienstes im Objekt) realisieren.



IDE Visual Studio 2003

IDE <=> Integrated Development Environment

Profile

Einstellen auf vb- Entwickler

Projekte und Projektmappen


Sichten auf den Code

Fenster

Position

Info

Projektexplorer

Asicht/..

Aufzählung aller Projekte einer Projektmappe. Zu jedem Projekt werden alle Dateien und Verweise aufgelistet

Codefenster

Ansicht/Code (F7)

C#- Code

Klassenansicht

Ansicht/..

Auflisten aller Klassen pro Projekt. Pro Klasse werden Basisklassen, Felder, Eigenschaften und Methoden aufgelistet

Objektbrowser

Ansicht/...

Zu allen Namensräumen innerhalb eines Projektes werden die Klassen angezeigt.

Einstellungen

Schriftart im Editor

Extras/Optionen/Umgebung/Schriftart

Sparchspezifisches Syntaxhighlighting, Intellisense

Extras/Optionen/Text Editor

Option Explicite, Strict für alle Projekte festlegen

Extras/Optionen/Projekte

Aufgabenliste

Tastenkombination: Strg + Alt + K

Dient zur Planung des Projektverlaufes. Die Elemente zur Planung sind Aufgaben. Jeder Aufgabe hat eine Priorität.

Funktionen:

Die einzelnen Kategoriene können im Aufgabenfenster über das Kontextmenü der Aufgabenliste abgerufen werden.

Steuerung der IDE über Kommandozeilen

Die IDE kann über Kommandozeilen- Befehle gesteuert werden. Dazu ist das Befehlsfenster über Ansicht/Andere Fenster/Befehlsfenster zu starten. Durch eingabe von >cmd wird das Befehlsfenster in den Befehlsmodus umgeschaltet. Befehle um Unterprogramme aus den Menüs zu Starten haben allg. die Form Menüname.Aktion. Z.B. öffnen eines neuen Projektes kan gestartet werden durch Datei.NeuesProjekt.

Dynamische Hilfe

Aufg. Dynamische Hilfe öffnen, und im Quelltext Format- eingeben-> Infos zu Format aus der Hilfe holen.

VB.NET Compiler

Im folgenden werden die Stufen der Übersetzung eines VB.NET- Programmsdargestellt:


Übersetzen auf der Kommandozeile

Im Folgenden wird ein einfaches Programm erstellt, welches auf der Kommandozeile den String "Hallo Welt" ausgibt. Anhand des Programmes wird die Kompilation in MSIL sowie das Kompilat selbst untersucht.

Beispiel Hallo Welt

Legen sie eine Datei namens Hallo.vb an.

=> Quelltexte werden in Unicode- Dateien mit der Endung vb gespeichert.

' VB.NET Kennenlernen
' Kommentare sind einzeilig und werden mit einem Hochkomma (') eingeleitet
' Alle Prozeduren und Funktionen müssen in einem Modul-
' oder Klassenblock eingeschlossen werden
Module m1

    ' Die Prozedur Main hat eine besondere Bedeutung: Beim Programmstart 
    ' wird vom Lader des Betriebssystems an diese die Kontrolle übergeben
    Sub Main() 

        ' Hier wird ein Unterprogramm aus der Bibliothek System.dll aufgerufen
        ' Mittels des Unterprogramms Console.WriteLine erfolgt die Ausgabe
        ' der Zeichenkette "Hallo Maja" auf der Kommandozeile
        System.Console.WriteLine("Hallo Maja")

    End Sub

End Module

Übersetzen

Das Beispielprogramm kann auf der Kommandozeile (Visual- Studio- Tools/Command Prompt) durch folgenden Befehl kompiliert werden:

c:\vb-kurs\vbc hallo.vb /r: System.dll

Die Option /r weist den Compiler an, Einsprungpunkte für Unterprogramme aus der Bibliothek System.dll anzulegen.

Präprozessordirektiven

Mittels Präprozessordirektiven können Abschnitte von der Kompilation ausgeschlossen werden.

# const

Mit #const kann eine Konstante definiert werden, die in Präprozessorblöcken für die bedingte Kompilation ausgewertet wird. Die Konstanten müssen als erste Anweisungen in einer Quelltextdatei definiert werden.

#const XX_GRUSS_MAJA = True
Module m1

    Sub Main() 
       :
   End Sub
End Module

Hier wird eine Konstante namens XX_GRUSS_MAJA deklariert.

Nicht deklarierte Konstanten in Präprozessorblöcken werden durch Nothing ersetzt und stellen damit den boolschen Wert false dar.

#if ... then #else

In Abhängigkeit von bedingten Konstanten können Abschnitte im Quelltext von der Kompilation ausgeschlossen werden oder nicht:

#const XX_GRUSS_MAJA = True
Module m1

    Sub Main() 

#if XX_GRUSS_MAJA then
        System.Console.WriteLine("Hallo Maja")
#else
        System.Console.WriteLine("Hallo Marina")
#endif

   End Sub
End Module

In diesem Beispiel wird die Zeile zwischen #else ... #endif nicht kompiliert. Wenn die erste Zeile (#const ...) auskommentiert wird, dann erfolgt keine Kompilation für die Zeile zwischen #if ... #else.

# region

Dient zur logischen Gliederung des Quelltextes. Die IDE kann Regionen wahlweise auf- und zuklappen. Bsp.:

#region "mm"
  sub p1
   ...
  end sub
  sub p2
   ...
  end sub
#end region

Aufbau eines VB.NET Programmes

VB.NET ist eine vollständig objektorientierte Programmiersprache. Im Mittelpunkt der Progammierung mit VB.NET steht

  1. die Beschreibung des Aufbaus von Objekten durch Klassendeklarationen

  2. das Senden von Nachrichten an Objekte durch Methodenaufrufe

  3. die Reaktion auf asynchrone Nachrichten/Ereignisse durch Ereignisse

Die gesamte Logik muß in Klassendeklarationen verpackt werden. Es gibt 2 Arten von Klassendeklarationen:

Module

Class

Alle Elemente sind implizit shared

Zugriff auf die Elemente muss individuell festgelegt werden

Folgendes Beispiel zeigt ein einfaches Befehlszeilenprogramm. Es wird durch eine Modul- Klassendeklaration realisiert.

Module Module1

    Class class1

        Public x As Short

        Sub New() ' Konstruktor
            x = 99
        End Sub

        Function add_to_x(ByVal s As Short)
            Return x + s
        End Function
    End Class

    Sub Main()

        ' Hier steht ein Kommentar

        Dim x, y As Short
        Dim c As New class1

        x = 1

        ' Werte von x aus Main und x aus c ausgeben

        Console.WriteLine("Wert von x= {0:D}", x)
        Console.WriteLine("Wert von c.x= {0:d}", c.x)

        ' Eine Memberfunktion von class1 aufrufen
        y = c.add_to_x(5)

        ' Das Ergebnis in y ausgeben
        Console.WriteLine("Wert von c.x= {0:d}", y)

        ' Warten auf eine Eingabe des Benutzers
        Console.ReadLine()

    End Sub

End Module

Literale

Menge

Beispiel

ganze Zahlen, dezimal

123

ganze Zahlen, Hexadezimal

&HAF

ganze Zahlen, Oktal

&O73

negative Zahlen

-123

rationale Zahlen

123.4

rationale Zahlen in Exponentialschreibweise

1.23e4

Zeichen

"A"C

Zeichenketten

"ABC"

Wahrheitswerte

true oder false

Datumsangaben (ami- Format MM/DD/YYYY)

#02/13/2004#

Operatoren

Operator

Beschreibung

( )

Klammern

^

Potenzieren

-

negatives Vorzeichen

* /

Multiplikation und Division

\

Integer Division

Mod

Modulo bzw. Rest aus Division, z.B. 7 Mod 3 = 1 denn 2*3 + Rest 1 = 7

+ -

Addition und Subtraktion

< > =

kleiner als, größer als, gleich

<> <= >= Like Is TypeOf

ungleich, kleiner gleich, größer gleich wie ist Typ-von

Not

logisches NICHT (Negation)

And Or

logisches UND, logisches ODER

Xor Equ

logisches Exlisiv ODER, Äquivalenz

Variablen

Unsere Programme realisieren Algorithmen, mit denen wir Daten verarbeiten. Um Zugriffe auf die Daten im Computerspeicher zu formulieren, muß uns die Programmiersprache entsprechende Ausdrucksmittel zur Verfügung stellen.

Ein elementares Ausdrucksmittel für Speicherzugriffe sind Variabeln.

Unter Variabeln können wir uns benannte Speicherplätze vorstellen. Variabeln sind immer vor ihrer Verwendung im Programmtext mittels einer Deklaration zu vereinbaren. In der Deklaration wird der zu verwendende Name für den Speicherplatz und der Datentyp festgelegt.

Deklaration in VB.NET

Zugriffsmodifikatoren Variabelname As Datentyp [= Startwert]

Der Datentyp steht für eine Klasse von Daten. Beispielsweise verbirgt sich hinter dem Datentyp Integer die Menge aller ganzen Zahlen im Intervall [-32768, 32767]. Der Datentyp bestimmt, wie die Informationen als Dualzahlen im Speicher zu verschlüsseln sind, und wieviel Speicherplatz für die Variabel benötigt wird. So werden Variabeln vom Typ Integer vom Dezimal- ins Dualsystem konvertiert, und für sie ein Speicherplatz von 16bit = 2Byte reserviert.

VB.NET Datentypen

Die primitiven Typen sind im Namespace System definiert:

VB.NET

CTS

Wertebereich

Literale

Boolean

System.Boolean

{true, false}

true


System.SByte

[-128, 127]

99

Byte

System.Byte

[0, 255]

255

Char

System.Char

[0, 65535]

"A"C

Short

System.Int16

[-32768, 32767]

199S


System.UInt16

[0, 65535]

199

Integer

System.Int32

[-2147483648, 2147483647]

199


System.UInt32

[0, 4294967295]

199 oder 199U

Long

System.Int64

[-9223372036854775808, 9223372036854775807]

199 oder 199L


System.UInt32

[0, 18446744073709551615]

199 oder 199UL

Single

System.Single

[-3.402823E+38, 3.402823E+38]

3.14 oder 3.14F

Double

System.Double

[-1.79769313486232E+308, 1.79769313486232E+308]

9.0 oder 9D

Decimal

System.Decimal

[0, 79.228.162.514.264.337.593.543.950.335]

125.99M

String

System.String

0- 2 Mrd. Unicodezeichen

"Hallo Welt"

Date

System.DateTime

00001-1-1 0:0:0 bis 9999-12-31 23:59:59

#5/31/1993#

Object

System.Object

 

 

Zugriffsmodifikatoren

Durch Zugriffsmodifikatoren wird das Prinzip der Kapselung in VB realisiert. Über Zugriffsmodifikatoren wird zur Entwurfszeit gesteuert, von welchen Programmteilen aus auf eine Variable zugegriffen werden kann. Dadurch können Implementierungsdetails von Bibliotheken verborgen werden. Sinn macht die Diskussion der Zugriffsmodifikatoren erst im Zusammenhang mit Klassen. An dieser Stelle wird nur der Zugriffsnodifikator Dim und Static eingeführt:

Zugriffsmodifikator

Beschreibung

Nicht deklarierebar in

Dim

nur im Block sichtbar, in dem deklariert wurde


Initialisierung

Für Variablen in statischen Methoden erfolgt eine automatische Initialisierung. Variablen in nichtstatischen Methoden müssen manuell initialsiert werden:

Dim i as int = 0

Blockstruktur, Sichtbarkeit und Lebensdauer von Variablen


Statische Variablen

In Sonderfällen kann es sinvoll sein, die Lebensdauer von Variablen in Funktionen und Prozeduren über die Blockgrenzen hinaus zu verlängern. Soll z.B. Protokolliert werden, wie oft eine Methode in einem Programm schon aufgerufen wurde, dann muß eine Zählervariable bereitgestellt werden, die wie eine Globale Variable zu Programmstart initialisiert und erst bei Programmende vernichtet wird.

Module Utils

   Function MakeID() as Long

     static id as Long = 0
     id += 1
     return id

   End Function

End Module

Elementare Ein/Ausgabe

Beispiel:

Dim preis As Dezimal = 99.45
Console.WriteLine("Preis: {0,10:########.##}€", preis)

Formatzeichenfolgen

Über Formatzeichenfolgen wird abhängig vom Datentyp die Darstellung eines Wertes als String gesteuert. Es gibt Formatzeichenfolgen für:

Formatzeichenfolgen für nummerische Typen

Formatzeichenfolgen bestehen aus einem Formatbezeichner und optional aus der Angabe einer Genauigkeit XX. Um eine Zahl mit max. 3 Nachkommastellen auszugeben, kann folgende Formatzeichenfolge verwendet werden:

N3

Folgende Formatbezeichner sind vordefiniert:

Formatbezeichner

Bedeutung

Beispiel

Resultat

C

Währungsbetrag

(99.490).ToString("C")

99,49 €

D

Ganzzahliger Wert. Die Genauigkeit definiert die minimale Ausgabebreite. Sollte die darzustellende Zahl die minimale Ausgabebreite nicht erreichen, dann wird mit führenden 0-en aufgefüllt

(123).ToString("D5")

00123


E

Zahl in Exponentialschreibweise

(99.49).ToString("E")

9,95E+005

F

Festkomma. Die Genauigkeit gibt eine feste Anzahl von Nachkommastellen an

(99.49).ToString("F1")

99,5

G

Allgemein- Formatierung erfolgt abhängig vom Typ der Zahl

(99.49).ToString("G")

99,5

N

Zahl (allgemein). Die Genauigkeit beschreibt die Anzahl der Nachkommastellen

(99.49).ToString("N")

99,49

P

Prozentzahl. Der Wert wird mit 100 multiplizieret und mit einem Prozentzeichen versehen

(0.15).ToString("P")

15,00%

H

Hexadezimal

(0xA1).ToString("H")

A1

R

Stellt Zahlen so als Zeichenkette dar, daß sie aus diesen ohne Genauigkeitsverlust wieder zurückkonvertiert werden können.

(99.49).ToString("R")

99,49

Neben vordefinierten Formatzeichenfolgen können Formate wie im obigen Beispiel auch selbst definiert werden. Siehe dazu: Benutzerdefinierte Formatzeichenfolgen

Formatzeichenfolgen für Datumstypen

Formatbezeichner

Bedeutung

Beispiel

Resultat

d

Kurzes Datumsformat

DateTime.Now.ToString("d")

27.04.06

D

Langes Datumsformat

DateTime.Now.ToString("D")

27. April 2006

T

Zeitformat

DateTime.Now.ToString("T")

12:17:59

s

ISO 8601 konformes Datumsformat. Werte sind sortierbar. Dieser Typ wird z.B. in XML- Schema angewendet

DateTime.Now.ToString("s")

2006-04-27T12:17:47

Formatzeichenfolgen für Aufzählungstypen

Formatbezeichner

Bedeutung

Beispiel

Resultat

G

Stellt Wert eines Aufzählungstyps als String dar, falls möglich. Andernfalls wird der Wert als Integer- Zahlenwert dargestellt

(SUnits.cm).ToString()

"SUnits.cm"

F

Stellt Wert eines Aufzählungstyps als String dar, falls möglich. Andernfalls wird der Wert als Integer- Zahlenwert dargestellt

(SUnits.cm).ToString()


D

Stellt Wert eines Aufzälungstyps als dezimalen Integer dar

(SUnits.cm).ToString()

2

X

Stellt Wert eines Aufzälungstyps als hexadezimalen Integer dar

(SUnits.cm).ToString()

0x2

ToString und Formatierung


Ausgabe mit IFormatProvidern

Imports System.Globalization;

' Kopie des aktuell wirksamen Formatproviders erzeugen
Dim nif as NumberFormatInfo 
nif = CType(System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.Clone(),  NumberFormatInfo)

' Währungssysmbol auf Dollar umstellen
nif.CurrencySymbol = "$"

' Ausgabe eines Währungswertes
Dim preis as Double
preis = 99.99
Console.WriteLine(preis.ToString("C", nif))

Composit- Formating

In Methoden wie Console.WriteLine("Formatstring", object, ...) können Textkonstanten und Formatblöcke, die Formatzeichenfolgen für auszugebende Parameter enthalten, kombiniert werden. Dies wird als Composit- Formating bezeichnet. Soll z.B. ein Längenmaß ausgegeben werden, welches aus dem Wert und der Längeneinheit besteht, dann könnte dies durch folgende Anweisung erfolgen:

Console.WriteLine("Längenmaß: {0,5:N} {1,2}", LMasz.value, LMasz.unitToString());

Ein Formatblock hat folgende Syntax:

{ParamListenIndex[,alignment][:Formatzeichenfolge]}

Der ParamListenIndex bezeichnet den Parameter aus der Parameterliste, dessen Wert durch den Parameterblock formatiert werden soll. Das Alignment definiert die Ausrichtung und mindestbreite. Positive Werte stehen für eine Rechtsausrichtung, negative für eine Linksausrichtung.

Enumerations

Endliche Mengen lassen sich durch Aufzählungen modellieren (Enumarations). Beipiel:

Enum enumLaengenEinheiten
  mm
  cm
  dm
  m
  km
  AE
  LichtJahr
End Enum

Datenstrukturen

Datenstrukturen werden deklariert durch Blöcke mit dem Schlüsselwort Structure (bei VB 6.0 Type). Jedes Element einer Strukture muß mit einem Zugriffsmodifikator versehen werden (Public, friend, Protected, Private). Dim entspricht dem Zugriffsmodifikator Public.

Structure Point 
  
  Dim x as Double
  Dim y as Double

End Structure

Steuerung der Programmausführung

In seiner Grundbetriebsart lädt der Computer eine Anweisung nach der anderen aus dem Arbeitsspeicher und führt sie aus. Viele Algorithmen erfordern jedoch, daß einige Abschitte aus den Anweisungslisten nur unter bestimmten Bedingungen auszuführen sind (z.B. „Wenn bis zum Tag X kein Zahlungseingang erfolgte, dann Mahnung abschicken“) oder wiederholt werden müssen. Um dies zu ermöglichen, verfügt der Computer über spezielle Anweisungen, die den Befehlszählerstand manipulieren. Sie bewirken, daß nach ihrer Ausführung das Programm an einer beliebigen neuen Adresse fortgesetzt wird. Aufgrund dieser Wirkung werden sie Sprunganweisungen genannt.

In VBA sind die Sprunganweisungen in Form von bedingt ausführbaren, oder bedingt wiederholbaren Programmabschnitten implementiert.

Bedingt ausführbarer Programmabschnitt

Der bedingt ausführbare Programmabschnitt entspricht einer Wenn ... dann Regel.

IF Bedingung Then
   Anweisung 1
   Anweisung 2
       :
   Anweisung n
End IF

Trifft die Bedingung nicht zu, dann kann anschließend mit dem Schlüsselwort Else ein Programmabschnitt als Alternative formuliert werden:

IF Bedingung Then
   Anweisung 1
       :
   Anweisung n
Else
   Anweisung n+1
       :
   Anweisung n+m
End IF

Gibt es mehrere Alternativen, die von Zusatzbedingungen abhängig sind, dann können diese in ElseIf- Blöcken formuliert werden:

IF Bedingung Then
   Anweisung 1
       :
   Anweisung n
ElseIF Bedingung2
   Anweisung n+1
       :
   Anweisung n+m
End IF

Ist die Ausführung mehrerer Programmabschnitte vom Wert eines einzigen Ausdrucks abhängig, dann kann alternativ zu ElseIf eine vereinfachte Schreibweise mittels Select Case Block gewählt werden:

Select Case Ausdruck
Case Wert1
     Anweisung 1
         :
     Anweisung n
Case Wert2
     Anweisung n+1
         :
     Anweisung n+m
Case Wert3
  :
Case Else
     Anweisung 
End Select 

Bedingt wiederholbarer Programmabschnitt

Es handelt sich hierbei um Programmabschnitte, die sooft wiederholt werden, solange eine Bedingung zutrifft (wahr ist). Sie werden gewöhnlich als Schleifen bezeichnet. Zwei elementare Formen der Schleifen werden unterschieden: die abweisende, und die nichtabweisende Schleife.

Bei der abweisenden Schleife wird stets am Anfang des Programmabschnittes geprüft, ob die Bedingung für eine Ausführung des Abschnittes erfüllt ist. Wenn ja, dann wird der Programmabschnitt ausgeführt, und am Ende der Befehlszähler wieder auf die Startadresse des Programmabschnittes gesetzt. Gilt die Bedingung weiterhin, dann erfolgt eine wiederholte Ausführung des Programmabschnittes. Trifft die Bedingung nicht zu, dann wird der Programmabschnitt übersprungen.

DO Bedingung
   Anweisung 1
   Anweisung 2
       :
   Anweisung n
Loop

Bei der nichtabweisenden Schleife wird die Bedingung erst am Ende des Programmabschnittes überprüft. Trifft sie zu, dann wird der Befehlszähler auf den Abschnittanfang gesetzt, und dieser wiederholt. Sonst wird mit der nachfolgenden Anweisung fortgesetzt.

Da die Bedingung erst am Ende des Abschnittes überprüft wird, wird der Abschnitt immer mindestens einmal ausgeführt.

DO
   Anweisung 1
   Anweisung 2
       :
   Anweisung n
Loop Bedingung

Sind Datenfelder fester Länge zu durchlaufen, oder Berechnung mit einer vorgegebenen Zahl wiederholt auszuführen, dann bietet sich die For...to ... next Schleife an:

FOR i = <Startwert> TO <Endwert> [STEP <Schrittweite>]
   Anweisung 1
   Anweisung 2
       :
   Anweisung n
Next

foreach

For Each el [as Type] in Collection 
   ...
Next

Arrays

Zur Verarbeitung tabelarischer dienen in VB Arrays. Durch die Deklaration eines Arrays werden im RAM n Speicherplätze zur Aufnahme von Werten des Typs x reserviert.

Deklaration eines Arrays hat folgenden Aufbau:

Dim a(3) as Integer
    | |       +----- Typ der Einträge
    | +------------- größter Index eines Eintrages
    +--------------- Name des Arrays

Nach einer Arraydeklaration ergibt sich folgendes Format im Arbeitspeicher:


Der Zugriff auf die Elemente eines Arrays erfolgt über den Namen und den Indize:

Dim x as Integer

' x hat nach Ausführung dieser Anweisung den Wert 2
x = a(2)
    | +--- Indize (Platznummer)
    +----- Arrayname

Die Indizes können dynamisch zur Laufzeit festgelegt werden. Damit ist eine komfortable Verarbeitung der Arraydaten in Schleifen möglich:

Dim i as Integer, s as Long

' s enthält nach der Schleife die Summe aller Einträge
for i = 0 to 3
   s = s + a(i)
next

Initialisierung von Arrays

Dim primz() as Integer = {2, 3, 5, 7, 11}

Anzahl der Einträge bestimmen

Dim anz_elems as Int32 = primz.length  'Anzahl der Elemente in über alle Dimensionen
Dim anz_dims  as Int32 = primz.rank    'Anzahl der Dimensionen eines Arrays

Zuweisen und Kopieren

Durch Zuweisung wird nur eine Referenz erzeugt, jedoch keine Kopie.

Dim prim2() As Int32 = prim

Die Methode Clone() eines Arrays erzeugt eine 1:1 Kopie

Dim prim3() As Int32 = prim.Clone()

Redimensionierung

Zur Laufzeit können die Dimensionen eines dynamischen Arrays mit der Prozedur ReDim <arrayName>( <neuerMaxIndex>) vergrößert und verkleinert werden wie folgt:

:
ReDim Preserve a(6) 
' Das Array wird um 3 Elemente vergrößert, wobei der alte Inhalt erhalten bleibt
:
ReDim a(9) 
' Das Array wird wiederum um 3 Elemente vergrößert. Diesmal wird der alte Inhalt jedoch nicht
' erhalten (Preserve fehlt)

Aufg.:

  1. Min/Max- Suche,

  2. Sortieren

  3. Messwerterfassung (akt. Wert, dyn. Mittelwert)

Datum und Uhrzeit

Grundlage für die Datumsberechnung ist ein linearer Zeitstrahl, der in Ticks unterteilt ist. Ein Tick hat die Dauer von 10-7s (zehnmillionstel Sekunde). Zeitpunkte auf dem Zeitstrahl werden durch Werte vom Typ Date angegeben. Ein Datumswert wird hat das Format #M/D/YYYY# (amerikanisches Datumsformat).


Date basiert auf System.DateTime. Die Konstruktoren von System.DateTime sind mehrfach überladen:

dim dat1 as New System.DateTime(Ticks)
dim dat2 as New System.DateTime(YYYY, MM, DD)
dim dat2 as New System.DateTime(YYYY, MM, DD, hh, min, sec, millisec)

Zur Darstellung von Zeiträumen dient die Klasse TimeSpan.

Strings

Siehe .NET Doku

Teilstrings ausschneiden

Dim txt as String = "Anton,Berta,Cäsar"
Console.WriteLine(txt.Substring(6, 5))

Umwandeln in Groß- oder Kleinschreibung

Dim txt as String = "Hallo Welt"

Console.WriteLine("Alles groß: {0}", txt.ToUpper())
Console.WriteLine("Alles klein: {0}", txt.ToLower())

Startposition von Teilstrings bestimmen

Dim txt as String = "Anton,Berta,Cäsar"
Dim pos as Int32  = txt.IndexOf("Berta")

Einfügen in Strings

Dim txt as String = "Anton,Berta,Cäsar"
txt = txt.Insert(txt.IndexOf("Berta"), "Aladin,")

Auftrennen von Zeichenfolgen

Dim txt as String = "Anton,Berta,Cäsar";
Dim namen() as String = txt.Split(","c);

Splitten mittels Reguläre Ausdrücke

Dim r As Regex = New Regex("\s*=\s*")
Dim aw() As String = r.Split("Durchmesser = 199")
Console.WriteLine("Attribut {0} hat Wert {1}", aw(0), aw(1))

Ersetzen mittels Regulärer Ausdrücke

' In folgendem String sollen alle Vorkommen von keinen durch [] markiert werden
txt = "Das Pferd frisst keinen Gurkensalat. Ich habe keine Ahnung warum"
Dim txt_neu As String = Regex.Replace(txt, "keinen", "[keinen]")
Console.WriteLine(txt_neu)

Aufgaben

  1. Romzahlkonverter

  2. Zählen der Buchstabenhäufigkeit in gegebenen Texten

Funktionen und Prozeduren

Mathematische Funktionen

Die wichtigsten mathematischen Funktionen sind im Math- Objekt des Namespace System enthalten.

Optionale Parameter

Beispiel: Eine Funktion soll implementiert werden, welche den Zeitraum zwischen zwei gegebenen Daten bestimmt. Als Standard wird der Zeitraum in Sekunden ausgegeben. Optional kann die verstrichene Zeit aber auch in Minuten, und Stunden ausgegeben werden:

Function Zeitraum_zwischen(ByVal start As Date, ByVal ende As Date, Optional ByVal einheit As String = "sec")
        Dim ticks As Long = Math.Abs(start.Ticks - ende.Ticks)
        Dim zr As New TimeSpan(ticks)
        Select Case (einheit)
            Case "sec"
                Return zr.TotalSeconds
            Case "min"
                Return zr.TotalMinutes
            Case "hh"
                Return zr.TotalHours
            Case Else
                Throw New Exception("Unbekannte Zeiteinheit")
        End Select

    End Function

Aufgabe:

Die Funktion Zeitraum_zwischen(...) zur Berechnung von Zeiträumen in Minuten und Stunden anwenden.

Parameterarrays

Beispiel:

Function summe_aus(ByVal ParamArray summanden( ) As Double)

        Dim i As Integer, sum As Double
        For i = 0 To summanden.GetUpperBound(0)
            sum += summanden(i)
        Next

        Return sum

 End Function

Aufgabe:

Die Funktion summe_aus (...) zur Berechnung der Summe verschiedener Listen einsetzen.

Delegate (Funktionszeiger)

Komponeten wie z.B. Formulare und strombasierte XML- Parser können über Ereignisroutinen (Eventhandler) an die Wünsche des Anwenders angepasst werden. Ereignisroutinen werden individuell vom Anwender erstellt und ähneln gewöhnlichen Prozeduren. Anschießend muß der Komponete die Ereignisroutinen bekannt gemacht werden. In C++ benutzt man dazu z.B. Funktionszeiger. Da VB.NET keine Zeiger bereitstellt, gibt es ein Sprachkonstrukt, die sog. Delegats (Delegierungen). Es handelt sich hierbei letzendlich um typisierte Funktionszeiger, deren Wert jedoch nicht geändert werden darf.

Deklaration eines Delegate

Jeder Delegate muß vor seiner Verwendung deklariert werden:

[Zugriffsmodifikator] Delegate Methodendeklaration
z.B.:
Public Delegate OnDirOpen(name as String)

Namespaces

Namespaces dienen zur Abgrenzung der Namensmengen zwischen verschiedenen Teilen von Bibliotheken und Programmen.

Namespace outer 

  Namespace inner 

     ' Deklaration des Namens x im Namespace outer.inner
     public x as Integer

  End Namespace

End Namespace

// Zugriff auf x 
outer.inner.x = 99;

Imports- Direktive

Imports Namespace
Imports Alias = Namespace

Objekte und Klassen in .NET

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.


Objektdiagramm


Beispiel für Objekt: Dateisystem




Aufgaben:

Beschreiben Sie folgende Systeme durch Objektmengen. Stellen Sie die Objekte durch Objektdiagramme dar.

  1. Bankkonto

  2. Geometrische Figuren

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.



Klassendeklaration

In VB.NET werden Klassen durch

Lebenszyklus eines Objektes


Konstruktor und Destruktor



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



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;
  }
}

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);

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

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

Events

Klasse mit Events definieren

class CAuto 

     : 

   Public vx as Single

   Public Event Bremsen()

   Public Sub fahren(pvx as Single, t as Single)

     if pvx < vx Then
        RaiseEvent Bremsen()
     End If 

   End Sub
    
     :

End Class

Eventhandler zuweisen

Module M1

   Sub OnBremsen()
      Console.WriteLine("Quietsch")
   End Sub     

   Sub Main()

      Dim bmw as New CAuto

      AddHandler bmw.Bemsen, AdressOf OnBremsen
      

   End Sub

End Module

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

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.




Definition von Vererbungsbeziehungen

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:

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:

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

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

Ü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

Ü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)

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.

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

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

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.




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

Fehlerbehandlung

Fehlerbehandlung kann klassisch mittels dem Err Objekt (unstrukturiert) bzw. modern mit dem try ... throw ... catch Block erfolgen.

Fehlerobjekt auswerfen

Throw new Exception("Fehlermeldung");

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

Hierarchie der Ausnahmen


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

.NET Datentypen

Alle Typen sind auf den Basistyp System.Object rückführbar. D.h. alle Typen verfügen über die Eigenschaften und Methoden von System.Object.


Referenztypen vs Wertetypen

Die Menge aller Typen, die sich von System.Object ableiten, kann in zwei Teilmengen aufgeteilt werden: den Referenztypen und den Wertetypen. Die Wertetypen werden grundsätzlich auf dem Programmstack angelegt und entsprechen den eigebauten Typen in älteren Programmiersprachen.


Referenztypen erfordern eine Instanzieirung in 2 Schritten:




Boxing und Unboxing- Konvertierung

Zwecks erhöhung der Ausführungsgeschwindigkeit werden Wertetypen auf dem Stack wie in allen anderen nicht .NET- Sprachen als reine Werte abgelegt. Da aber alle Typen konmplexe Objekte darstellen, erfogt eine Konvertierung, wenn ein Wertetyp in einem Objektkontext aufgerufen wird. Dabei wird temporär auf dem Heap ein Objekt angelegt, und der Wert des Wertetypen hinenkopiert. Dies wird als boxing  bezeichnet.

char zeichen = 'A';     // vf ist ein Wertetyp und 
// Im folgenden wird der Wertetyp in einem Objektkontext eingesetzt (zeichen.isDigit())
// Hier wird auf dem Heap ein Objekt erzeugt, dessen Kopie zeichen aufnimmt.
string aussage = zeichen.isDigit() ? "Ziffer" : "keine Ziffer";  

Typ bestimmen

is Operator

Der Is- Operator ergibt True, wenn zwei Referenzen auf dasselbe Objekt verweisen:

If ref_a is ref_b
   return True
End IF

Typvergleich mittels TypeOf ... is

Mittels des typeof- Operators kann zu einer Klasse ein Typ- Objekt erzeugt werden. Er entspricht der statischen Methode System.Type.GetType(..).

if TypeOf a Is Integer Then 
   ....
end if

GetType() Methode

Jedes Objekt erbt von der .net Wuzel System.Object die Methode GetType. Diese liefert ein Type- Objekt, welches alle Metainformationen zu einem Typ enthält.

GetType(x as Object) - Operator

Der GetType(x as Object)- Operator ermöglicht es, zu einem beliebigen Typ (Klassenname) das Type- Objekt zu bestimmen, ohne das ein Instanz notwendig ist.

Implizite Typkonvertierung

Implizite Typkonvertierungen sind zwischen verwandten Datentypen möglich, wenn der Zieltyp mehr Informationen aufnehmen kann als der Quelltyp:




Explizite Typkonvertierung

Explizite Typkonvertierungen erzwingen die Umwandlung von einem Typ in einen anderen. Dabei gibt es jedoch verschieden starke Konvertierungsoperatoren. Auf der einen Steite gibt es die VB- Konvertierungsoperatoren, auf der anderen Seite die Operatoren der Klasse Convert.

VB

VB.NET

Convert-Klasse

x = Cbool(<expr>)

x = Ctype(<expr>, Boolean)

toBoolean(<expr>)

x = Cbyte(<expr>)

x = Ctype(<expr>, Byte)

toByte(<expr>)

x = Cchar(<expr>)

x = Ctype(<expr>, Char)

toChar(<expr>)

x = Cdec(<expr>)

x = Ctype(<expr>, Decimal)

toDecimal(<expr>)

Die Convert Funktionen sind am stärksten Konvertierungsfunktionen. Sie ermöglichen eine konvertierung zwischen an sich inkompatibelen Typen wie Zahlenwerte in Strings in nummerische Werte von Int32 etc.

Reflektion

Die in den Type- Objekten gespeicherten Metainformationen beschreiben die Struktur einer Klasse vollständig. Beispielsweise können alle Member einer Klasse wie folgt aufgelistet werden:

Imports System
Imports System.Reflection


class CTest 
  Dim ganzZahl as Integer
  enum EPartei
       gut
       boese
       gerecht
  End Enum
  Function TueWas() as Integer
     ganzZahl += 1
     Return ganzZahl
  End Function
End Class

:
    Sub Main()

        Dim t As Type

        t = GetType(CTest)

        ' Alle Felder, Eigenschaften und Methoden werden aufgelistet                 

        Dim minfos() As MemberInfo = t.GetMembers()

        For Each minfo As MemberInfo In minfos
            Console.WriteLine("{0}", minfo.ToString())
        Next

    End Sub

Aufgaben

  1. Entwickeln Sie eine Klasse CTypeBrowser, welche die Methode info(object) implementiert, die zu einem gegebenen Objekt alle Felder und Methoden auflistet.

Speziealwert Nothing

Nothing ist ein spezieller Wert, der jeder Variablen zugewiesen werden kann.

Zuweisung an Variable vom

bewirkt

Wertetyp

Die Variable wird auf ihren Standardwert zurückgesetzt (Strings z.B. auf leere Zeichenkette)

Referenztyp

Bei Objektvariablen verweisen diese nicht mehr auf das Objekt. Das Objekt wird jedeoch erst gelöscht, wenn die Garbage Collection keine Verweise auf das Objekt vorfindet.



Objektmodell von char


Objektmodell von String

Siehe .NET Doku

Char , Strings und Unicode

.NET unterstützt Unicode. Quelltexte können als Unicode- Dateien verpackt werden, und Zeichentypen wie char und string basieren auf 16bit Unicode. Folgendes Windows- Programm liefert einen Dialog mit einem kyrillischen Text:

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Vom Windows Form Designer generierter Code "
  :
#End Region

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' char verarbeiten Unicode- Zeichen
        Dim c1, c2, c3, c4, c5, c6, c7 As Char

        c1 = ChrW(1051)
        c2 = ChrW(1070)
        c3 = ChrW(1041)
        c4 = ChrW(1054)
        c5 = ChrW(1042)
        c6 = ChrW(1068)

        Dim str As String

        str += c1.ToString + c2.ToString + c3.ToString + c4.ToString + c5.ToString + c6.ToString

        lblDasWichtigste.Text = str


    End Sub
End Class

Mittels der Funktion ChrW(Zahl) wird eine nummerischer Unicode in ein Unicodezeichen umgewandelt. Der String aus den Unicodezeichen wird schließlich über ein Label (lblDasWichtigste) im Formular angezeigt.

Aufg.:
  1. Programm, welches in einer Textbox eine Teilmenge des Unicodes als Zeichencodetabelle ausgibt. Bsp: Währungssymbole von 20A1 bis 20AF

  2. Programm, welches alle Satzzeichen im Unicode ausfiltert und anzeigt

Collections

Collection werden im .NET durch Klassen gebildet, die Schnittstellen aus der folgenden Hierarchie implementieren:


Im Namensraum System.Collections werden zur allgemeinen Verwendung folgende Klassen bereitgestellt

ArrayList

Queue

Stack

Hashtable

implementiert IList

implementier ICollection

implementiert ICollection

implementiert IDictionary

Stellt Funktionalität eines gewöhnlichen Arrays dar, mit dem vorteil, daß Löschen von Elementen zu keinen Lücken führt.

Realisiert einen FIFO- Speicher

Realisiert einen Stapelspeicher

realisert effiziente Liste mit zugriff über nichtnummerische Indizes (Schlüssel)

ArrayList re_positionen = new ArrayList();




IEnumerable und ICollection


IList




IDictionary

Beschreibt eine Schnittstelle von Collections, in denen Werte unter bestimmten Schlüsseln abgelegt werden:





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.*")> 

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

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.

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

Serialisierung

Die Serialisierung ist ein Prozess, durch den Instanzendaten in eine Form umgewandelt werden, die speicherbar oder über Netzwerke übertragbar ist. Aus den serialisierten Daten kann schließlich wieder das Objekt zurückgewonnen werden. Der Prozeß der Rückgewinnung wird als Deserialisierung bezeichnet.

Im folgenden Bild wird die Serialisierung eines Objekts und anschließende Speicherung auf Festplatte sowie die Rückgewinnung durch Deserialisierung gezeigt. Durch Wahl eines speziellen Serialisieres werden die Instanzdaten im XML- Format gespeichert.


Voraussetzungen

Jedes Objekt, das serialisiert werden soll muß zu einer Klasse gehören, deren Deklaration das Attribut <Serializable> vorangestellt wurde. Durch <NonSerialized> werden Objekte explizit von der Serialisierung ausgeschlossen.

Imports System.IO
Imports System.Xml.Serialization
Module m1Serialisierung

    Public Sub Main()

        ' Verbindung mit Datenbank aufnehmen
        Dim con As New Odbc.OdbcConnection

        Try
            Dim dland As New CLand
            Dim i As Integer

            With dland
               .kennzeichen = "D"
               .name = "Deutschland"      
            End With

            ' Serialisierung

            Dim xmlserial As New XmlSerializer(GetType(CLand))

            Dim fs As New FileStream("cland.xml", FileMode.Create)

            xmlserial.Serialize(fs, dland)

            fs.Close()
            fs = Nothing


            ' Deserialisierung --------------------------------------------

            Dim fs2 As New FileStream("cland.xml", FileMode.Open)

            Dim neuland As CLand

            neuland = xmlserial.Deserialize(fs2)

            With neuland
                Console.WriteLine("------------------------------------------------------------------")
                Console.WriteLine("Ein Objekt namens Neuland wurde durch Deserialisierung gewonnen")
                Console.WriteLine("Inhalt: name= {0}, kennzeichen = {1}, zeit= {2}", .name, .kennzeichen, .erstellt_am)
            End With

        Catch ex As Exception

            Console.WriteLine("Es ist ein allg.  Fehler aufgetreten")
            Console.WriteLine("{0}", ex.Message)

        End Try



        Console.ReadLine()
    End Sub

End Module
Public Class CLand
    Private propLname As String
    Private propLkz As String
    '<NonSerialized()>
    Public erstellt_am As Date

    Sub New()
        ' leerer Konstruktor für XML- Serialisierung
        erstellt_am = Now
    End Sub

    Property name() As String
        ' Name eines Landes
        Get
            Return propLname
        End Get
        Set(ByVal Value As String)
            propLname = Value
        End Set
    End Property

    Property kennzeichen() As String
        Get
            Return propLkz
        End Get
        Set(ByVal Value As String)
            propLkz = Value
        End Set
    End Property
End Class