1 VB.NET
1.1 BASIC war mal eine Anfängersprache ...
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 Interpreter Sprache konzipiert. Ein geringer Umfang an
Befehlen, die Invarianz gegenüber der Groß/Kleinschreibung
und die Interaktivität durch den Interpreter führten dazu,
dass BASIC insbesondere unter Anfängern beliebt wurde.
1.2 VB.NET Compiler
Im folgenden werden die Stufen der Übersetzung
eines VB.NET- Programms dargestellt:
1.2.1 Ü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.
1.2.1.1 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
1.2.1.2 Ü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.
1.2.2 Präprozessordirektiven
Mittels Präprozessordirektiven können
Abschnitte von der Kompilation ausgeschlossen werden.
1.2.2.1 # 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 booleschen Wert false dar.
1.2.2.2 #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.
1.2.2.3 # 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
1.2.3 Testaugaben mittels Debug und Trace Klassen
Bei der Entwicklung von Programmen muss der
Programmierer oft das Verhalten zur Laufzeit überwachen. Dazu
macht er hilfsweise Ausgaben von aktuellen Variablenwerten, dem
Ergebnis von Berechnungen etc.. Dazu bietet das .NET Framework ein
ideales Instrument, die Debug-
und Trace Klasse.
Die Debug- Klasse
bietet Unterprogramme zur testweisen Ausgabe und zum testweise prüfen
von Werten an:
' Testweise Ausgabe des Wertes x im Direkt/Ausgabefenster von VS2012
Debug.WriteLine("x= " & x)
' Testweise überprüfung, ob x größer 0 ist. Wenn nicht,
' dann wird eine Ausnahme ausgelöst
Debug.Assert(x > 0)
Wie die Präprozessorbefehle
können alle Unterprogrammaufrufe von Debug über einen
Compilerschalter wahlweise aus dem Quelltext vor der eigentlichen
Übersetzung entfernt werden. Die Schalter sind die Debug-
und Trace-
Preprozessorkonstanten.
1.3 Grundlegende Sprachelemente
1.3.1 Blöcke
Die elementarste Struktur aller
Programmiersprachen sind Blöcke. Ein Block ist ein
zusammenhängendes Stück Text (Programmcode), das durch
spezielle Schlüsselworte abgegrenzt wird.
Blockbeginn Schlüsselwort
Programmtext
Blockende Schlüsselwort
Im Folgenden einige
wichtige Blöcke in VBA als Beispiel:
Schlüsselwörter
|
Bezeichnung
|
Namespace <Blockname>
End Namespace
|
Definiert
einen Bereich, innerhalb dessen Namen eindeutig sein müssen.
Außerhalb des Blocks wird jeder Name durch das
Blocknamenspräfix eindeutig.
|
Modul <Modulname>
' Anweisungen
…
End Module
|
Container,
die Functions, Sub's und Variablen aufnehmen, die zu einem
Aufgabenkomplex gehören oder in einem sachlichen Zusammenhang
stehen.
Z.B.
können die Funktionen, die bei der Implementierung der
Teilschritte des Primzahlscanners entstanden (IstPrimzahl(z),
TesteAufTeiler(z,
t) und AllePrimzahlenIn(a,
b)) in einem Modulblock mit dem Namen Primzahlscanner
zusammengefasst werden.
|
Sub <Unterprogrammname>
' Anweisungen
...
End Sub
|
Unterprogrammblock: Schließt
Liste von Anweisungen ein, die über einen Namen geladen und
ausgeführt werden können
|
IF <Bedingung> Then
' Anweisungen
…
End IF
|
Bedingter Anweisungsblock:
Schließt Liste von Anweisungen ein, die nur ausgeführt
werden, wenn die Bedingung erfüllt ist.
|
Class <Klassenname>
' Anweisungen
…
End Class
|
Klassenblock. Fasst alle Sub,
Functions und Properties zusammen, die Objekte einer Klasse
besitzen.
|
1.3.1.1 .NET Einschlussdogma
VB.NET ist Bestandteil von .NET und unterliegt
damit der CLS (Common Language Spezification). Die verlangt, das jede
.NET Sprache streng objektorientiert ist. Damit muss jede Variable
und jede Prozedur in einem Klassen- oder Modulblock definiert werden.
"Freistehende" Variablen sind verboten.
Namespace N1
' Falsch ! Sub wurde außerhalb eines Class oder Module- Block deklariert
Sub TueWas()
…
End Sub
Module M1
' richtig ! Sub wurde innerhalb eines Class oder Module- Block deklariert
Sub TueWas()
…
End Sub
End Module
End Namespace
1.3.1.2 Verschachtlung
Die Anweisungslisten innerhalb von Blöcken
können wieder in Blöcke eingeschlossen werden, so dass eine
Baumstruktur entsteht. Man spricht von Verschachtlung.
Allgemein
|
Beispiel
|
Beginn Block1
' Anweisungen
...
Beginn Block2
' Anweisungen
...
End Block2
' Anweisungen
...
End Block1
|
Sub Hauptprogramm
A = 5
B = 4
IF A > B Then
Debug.Print "A ist größer als B"
End IF
End Sub
|
1.3.1.3 Namespaces
Namespaces dienen zur Abgrenzung der Namensmengen
zwischen verschiedenen Teilen von Bibliotheken und Programmen.
Namespace outer
Namespace inner
Modul MyMod
' Deklaration des Namens x im Namespace outer.inner.MyMod
public x as Integer
End Modul
End Namespace
Modul MyMod
' Deklaration des Namens x im Namespace outer.MyMod
public x as Integer
End Modul
End Namespace
// Zugriff auf x
outer.inner.MyMod.x = 99;
1.3.1.3.1 Imports- Direktive
Der Zugriff auf Typen und Funktionen , die in tief
verschachtelten Namensräumen definiert sind, kann zu einem sehr
unübersichtlichen Code führen. Durch die Imports- Direktive
kann am Anfang eine Namespace- Präfix vereinbart werden, das der
Compiler auf nicht auflösbare Namen anwenden kann.
Imports Namespace
Imports Alias = Namespace
1.3.2 Ausdrücke
Ein Ausdruck ist in VB.NET ein Konstrukt aus
Namen, Werten, Operatoren und Funktionsaufrufen, das zu einem Wert
ausgewertet werden kann. Die Auswertung wird als Evaluierung
bezeichnet.
Beispiele:
3 // wird zu 3 ausgewertet
3 + 4 // wird zu 7 ausgewertet
(3 + 4) * 2 // wird zu 14 ausgewertet
D // Auswertung liefert den Inhalt der Variable D
Math.Pi * D // wird zum Kreisumfang ausgewertet, wenn in über Variable D
// der Durchmesser bereitgestellt wird.
1.3.2.1 Bedingte Ausdrücke
Ein bedingter
Ausdruck ist eine spezielle VB.NET- Funktion mit drei Parametern:
Ausgangswert = IIF(Bedingung, ExprA, ExprB)
Zuerst wird die Bedingung evaluiert. Ergibt sie den Wert true,
dann wird ExprA evaluiert und deren Wert entspricht dem Ausgangswert.
Sonst entspricht der Evaluierte Wert von ExprB dem Ausganswert.
1.3.2.2 Funktionen
Eine Funktion bildet eine Liste von Eingangswerten
aus einen Ausgangswert ab:
E1 --+
|
Eingänge E2 --+-Funktion_f-> Ausgangswert
… |
En --+
Ein funktionale Abbildung wird in
VB.NET durch spezielle Ausdrücke, den Funktionsaufrufen
implementiert:
Funktionswert = Funktion_f (E1, E1, …, En)
| |_____________|
| |
Funktions- Parameterliste
name
In VB.NET gibt es bereits viele
eingebaute Funktionen. Beispiele:
' Eingabaute Funktionen
Sub TestBuildInFunctions()
Dim y As Double
' Sinusfunktion (Mathe, Trigonometrie)
y = Math.Sin(Application.Pi / 2)
Debug.Assert (y = 1.0)
Dim anzZeichen As String
' Zeichenkettenfunktion. Eingegebener Text wird auf die Anzahl
' der Zeichen des Textes abgebildet
anzZeichen = Len("Hallo Welt")
Debug.Assert (anzZeichen = 10)
Dim datum As Date
' Datumsfunktion: Die eingegebenen Werte (Jahr, Monat, Tag) werden
' auf einen VBA- Datumswert abgebildet
datum = DateSerial(2013, 11, 29)
Debug.Assert (datum = #11/29/2013#)
End Sub
1.3.3 Anweisungen
Ein Programmtext besteht in VB.NET aus
Anweisungen. Eine Anweisung ist ein ausführbarer Befehl. Befehle
können elementar oder komplex sein.
Elementare Befehle sind direkt ausführbar wie
z.B. einfache Sprungbefehle:
Goto SPRUNGMARKE
Komplexe Befehle setzen sich aus Speicherzugriffsbefehlen,
Operationen und Zuweisungen zusammen.
A = 3 * (B + 99)
Anweisungen werden entweder durch ein Zeilenumbruch - Zeichen oder
durch : getrennt.
Abschluss mit Zeilenumbruch
|
Abschluss mit :
|
Kombiniert
|
Blockbeginn Schlüsselwort
Anweisung_1
Anweisung_2
…
Anweisung_N
Blockende Schlüsselwort
|
Blockbeginn Schlüsselwort
Anweisung_1:Anweisung_2
Blockende Schlüsselwort
|
Blockbeginn Schlüsselwort
Anweisung_1:Anweisung_2
…
Anweisung_N
Blockende Schlüsselwort
|
1.3.3.1 Kommentar - Anweisung
Mit der Kommentar - Anweisung ' kann Text bis zum
Zeilenumbruch von der Übersetzung ausgeschlossen werden. Dies
kann man nutzen, um bei der Entwicklung temporär Code
abzuschalten oder Anmerkungen in den Programmkode einzufügen. Im
Folgenden einige Einsatzbeispiele für Kommentare:
' Eine Kommentarzeile
' Eine temporär abgeschaltete Anweisung
' A = 3 * B
B = 5 * C ' Ein Kommentar im Anschluss an eine Anweisung
1.3.3.2 Zuweisung
Eine Zuweisung ist eine spezielle VB.NET-
Anweisung der Form:
Variable = Ausdruck
Sie entspricht einem Kopierbefehl, wobei der evaluierte Ausdruck
rechts neben dem Gleichheitszeichen an den benannten Speicherplatz
(Variable) links neben den Gleichheitszeichen kopiert.
1.3.4 Literale
Literale gehören zu den Grundbausteinen einer
Programmiersprache und bezeichnen die Vereinigung der Mengen aller
Standard in VB.NET ist die Darstellung von
Zahlenwerten im dezimalen Zahlensystem (Basis 10). Der Wert von
logischen Aussagen kann durch die beiden Elemente true oder
false ausgedrückt
werden. Es gibt Literale für Datumswerte, die auf der US-
amerikanischen Notation basiert.
Menge
|
Beispiel
|
Festkommawerte
|
123
|
Festkommawert, hexadezimal
|
&HAF
|
Festkommawert, oktal
|
&O73
|
Festkommawert, dezimal
|
123.4D
|
Gleitkommawerte
|
123.4
|
Gleitkommawerte in Exponentialschreibweise
|
1.23e4
|
negative Festkomma und Gleitkommawerte
|
-123, -123.45
|
Zeichen
|
"A"C
|
Zeichenketten
|
"Hallo"
|
Wahrheitswerte
|
true
oder false
|
Datumsangaben (amerikanisches Format
MM/DD/YYYY)
|
#02/13/2004#
|
Wert einer leere Referenzvariable
|
Nothing
|
1.3.4.1 Spezialwert 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 Objekt variablen verweisen diese nicht
mehr auf das Objekt. Das Objekt wird jedeoch erst gelöscht,
wenn die Garbage Collection keine Verweise auf das Objekt
vorfindet.
|
1.3.5 Operatoren
Operatoren sind grundlegende Abbildungen von
Mengen in sich selbst. Beispielsweise ist die Addition zweier
Festkommazahlen ein Operator.
Eine Anweisung kann mehrere Operatoren enthalten
wie:
A = 3 * (B + 99)
In diesem Falle muss bei der Ausführung der Anweisung über
die Reihenfolge entschieden werden, in der die Operatoren anzuwenden
sind. Basis dafür ist die Priorität der Operatoren.
Operatoren mit höherer Priorität werden vor Operatoren mit
niedrigerer Priorität ausgeführt.
Im folgenden die Liste aller Operatoren von
VB.NET:
Priorität
|
Operator
|
Beschreibung
|
höchste
|
(
)
|
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
|
|
Not
|
logisches NICHT
(Negation)
|
|
And
Or
|
logisches UND,
logisches ODER
|
niedrigste
|
Xor
Equ
|
logisches Exlisiv
ODER, Äquivalenz
|
1.3.6 Variablen
Variablen sind benannte Speicherplätze.
In die Speicherplätze wird geschrieben oder aus ihnen wird
gelesen, indem auf diese der Zuweisungsoperator = mit einem Wert
angewendet wird:
' Speichern des Wertes 3.14 in meineVariable
meineVariable = 3.14
' Lesen eines Wertes aus meinerVariable und speichern in deinerVariable
deineVariable = meineVariable
1.3.6.1 Regeln für Variablennamen
Für
die Bezeichnung von Variablen gelten in C# wie in vielen anderen
Programmiersprachen auch Einschränkungen.
Erste
Zeichen muss ein Buchstabe sein:
Richtig:
A1
Falsch:
1A
Der
Name darf keine Leerraumzeichen enthalten
Richtig:
neuerMitarbeiter
Falsch:
neuer Mitarbeiter
Es sind nur
Buchstaben, Zahlen und der Unterstrich _ als Zeichen erlaubt
Richtig:
Preis_in_Euro
Falsch:
Preis_in_€
Der
VB.NET Compiler verarbeitet Unicode- Quelltextdateien. Damit sind
auch Variablennamen mit z.B. Umlauten zulässig
Dim akt_Ölpreis_in_Dollar as Double = 100.0;
Man sollte jedoch
bedenken, dass in internationalen Programmierteams Mitglieder, die
keine deutsche Tastatur besitzen, bei der Pflege solcher Quelltexte
unnötigen Aufwand haben.
1.3.6.2 Deklaration in VB.NET
Die im Programm verwendeten Variablen werden
entweder implizit oder explizit definiert.
1.3.6.2.1 Implizite Deklaration
Implizite Deklaration bedeutet, der Programmierer
weist erstmalig einem Namen einen Wert zu. Der VB.NET- Compiler
leitet dabei aus dem zugewiesenen Wert ab, wie viel Speicherplatz
benötigt wird.
' implizite Deklaration
meineVariable = 0
Die implizite Deklaration ist ein Relikt aus den Anfängen der
Sprache BASIC. Wird sie verwendet, dann können sich viele Fehler
in das Programm einschleichen, die erst zur Laufzeit entdeckt werden.
Beispiel
' impizite Deklaration von Variablen
meineVariable = 0
deineVariable = 0
'…
' Fehler ! Buchstabendreher führt zum impliziten Deklarieren einer neuen Variable
meineVariabel = deineVariable + 1
' Ausgegeben wird im Direktfenster "Wert von meineVariable: 0" !
Debug.Print "Wert von meineVariable: " & meineVariable
1.3.6.2.2 Explizite Deklaration
Mit der expliziten Deklaration werden einige
Nachteile der impliziten Deklaration von Variablen überwunden.
Bei der expliziten Deklaration muss der zu verwendende Name mittels
einer Dim- Anweisung festgelegt werden.
Dim Variablenname
1.3.6.2.3 Strikte Deklaration
Eine explizite
Deklaration kann noch genauer werden, indem zusätzlich der
Datentyp einer Variable vereinbart wird:
Dim Variablenname As Datentyp
Der Datentyp
steht für eine Klasse von Daten. Beispielsweise verbirgt sich
hinter dem Datentyp Integer die Menge aller ganzen Zahlen im
Intervall [-2147483648, 2147483647]. Der Datentyp bestimmt, wie die
Informationen als Dualzahlen im Speicher zu verschlüsseln sind,
und wie viel Speicherplatz für die Variable benötigt wird.
So werden Variablen vom Typ Integer vom Dezimal- ins Dualsystem
konvertiert, und für sie ein Speicherplatz von 32bit = 4Byte
reserviert.
Strikt deklarierte Variablen überwacht der
Compiler genauer. Wird versucht, z.B. einer Variable einen Wert
zuzuweisen, der inkompatibel mit ihrem Datentyp ist, dann meldet der
Compiler einen Fehler:
Dim x as Integer
x = "Hallo Welt" ' Compiler meldet Fehler
1.3.6.2.4 Explizite und stricte Deklaration erzwingen mittels Option Explicit
und Option Strict
Mittels folgender Anweisung an den Compiler kann
die explizite Deklaration aller Variablen erzwungen werden:
Option Explicit
Option Strict
Erzwingen bedeutet, dass der Compiler Fehler meldet, wenn ein
Variablenname verwendet wird, ohne das er vorher explizit und strikt
deklariert wurde.
Die Anweisung Option Explicit muss
als erste Zeile in einer vb- Quellkodedatei notiert werden.
In Visual Studio 2012
können diese Optionen für alle VB- Projekte eingestellt
werden unter
Extras/Optionen/Projekte und Projektmappen/VB Standard
1.3.6.2.5 Initialisierung
Variablen werden in VB.NET explizit oder implizit
deklariert.
Bei der impliziten Initialisierung wird der
Variable automatisch vom Compiler der Wert Nothing zugewiesen.
Im Falle einer Variable vom Typ Integer bewirkt dies, das die
Variable den Wert 0 erhält.
' Variable wird implizit mit dem Wert 0 initialisiert
Dim x as Integer
Die explizite Initialisierung besteht in der Zuweisung eines
Anfangswertes an die Variable in der Deklaration
' Explizite Initialisierung (allgemein) ...
Dim <Variablenname> as <Datentyp> = <Initialwert>
' … und im Beispiel
Dim x as Integer = 99
1.3.6.2.6 Typinferenz (ab .NET 3.5)
Achtung:
Das
Folgende Merkmal ist nur bei OPTION INFER ON verfügbar !
Mit Typinferenz wird ein Verfahren bezeichnet, das
aus dem Wert, mit dem eine Variable initialisiert wird, den Typ für
die Deklaration der Variable ableitet.
Typinferenz wurde im Zusammenhang mit LINQ
eingeführt, da der Datentyp des Ergebnisses einer LINQ- Abfrage
sich häufig erst aus der Abfrage ergibt.
Typinferenz ist nicht mit dem Verhalten bei Option
Strict Off gleichzusetzen, da bei der Typinferenz der Typ
nachträglich nicht geändert werden kann !
' Typinferenz: Deklaration ohne Typspezifikation-> Typ wird aus dem zugewiesenen Wert bestimmt
Dim i = 0
Dim str = "Hallo Welt"
' i ist nach wie vor streng typisiert
i = "Hallo Welt" ' => Fehler, da i vom Typ int
1.3.6.3 Elementare Datentypen (Wertetypen) in VB.NET
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 wie viel Speicherplatz für die Variabel benötigt wird.
So werden Variablen vom Typ Integer vom Dezimal- ins Dualsystem
konvertiert, und für sie ein Speicherplatz von 32bit = 4Byte
reserviert.
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 9
|
Decimal
|
System.Decimal
|
[0, 79.228.162.514.264.337.593.543.950.335]
|
125.99D
|
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
|
|
|
1.3.6.4 Enumerations als Teilmengen von Integer
Endliche Mengen lassen sich durch Aufzählungen
modellieren (Enumarations). Beipiel:
Enum enumLaengenEinheiten
mm
cm
dm
m
km
AE
LichtJahr
End Enum
Enumerationen sind Teilmenge vom
Typ int. Die Symbole in einem enum- Block vom Compiler
automatisch durchnummeriert, beginnend bei 0. Die Nummerierung kann
auch vom Programmierer erfolgen, wie der folgende Auszug aus der
Beispielbibliothek BatchProcessing zeigt:
'----------------------------------------------------------------------------
' Zustände eines Jobs
Enum JobStates
undefined = &H1 ' Job wurde erstellt, aber es ist noch keine JobId
' definiert worden
defined = &H2 ' Job wurde neu erstellt und JopId ist definiert
waiting = &H4 ' Job befindet sich in der Warteschlange vor der
' Bearbeitungsstation
processing = &H8 ' Job wird bearbeitet
pause = &H9, ' Bearbeitung des Jobs pausiert/wurde kurz unterbrochen
finished = &H10, ' Job wurde fertiggestellt
aborted = &H20, ' Bearbeitung des Jobs wurde abgebrochen
End Enum
Der Zugriff auf einen Enum- Wert
erfolgt über den Namen des Enums:
mJobState = JobStates.pause
1.3.6.5 Typkonvertierung
1.3.6.5.1 Implizit
Implizite Typkonvertierungen sind zwischen
verwandten Datentypen möglich, wenn der Zieltyp mehr
Informationen aufnehmen kann als der Quelltyp:
1.3.6.5.2 Explizit
Explizite Typkonvertierungen erzwingen die
Umwandlung von einem Typ in einen anderen. Dabei gibt es jedoch
verschieden starke Konvertierungsoperatoren. Auf der einen Seite gibt
es die VB- Konvertierungsoperatoren, auf der anderen Seite die
Operatoren der Klasse Convert.
VB 6
|
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 inkompatiblen Typen wie Zahlenwerte in Strings in
nummerische Werte von Int32 etc.
1.3.7 Referenztypen
Alle bis hier behandelten Datentypen sind
elementar. Das bedeutet z.B. das sie eine feste Länge besitzen,
und ihre Werte ihnen direkt zugewiesen werden können.
VB.NET kann aber mit viel komplexeren Daten
umgehen, sog. Objekten. Diese können einen variierenden
Speicherplatzbedarf zur Laufzeit haben. Ein Zuweisung eines Wertes
direkt an sie ist nicht möglich, da sich sich in der Regel aus
vielen elementaren Teildaten, Eigenschaften genannt, zusammensetzen.
Diese Art von Typen sind nicht elementar, und werden Referenztypen
genannt.
1.3.7.1 Objekt- Variablen
Objekte werden im Arbeitsspeicher anders verwaltet
als Variablen primitiven Typs. Sie werden im sog. Freispeicher
aufbewahrt, während die Variablen im Stapelspeicher residieren.
VB.NET kann nur direkt auf Variablen zugreifen.
Mit folgendem Trick gelingt der Zugriff auf Objekte: es wird eine
Variable angelegt und in diese die Speicheradresse des Objekts
geschrieben. Beim Zugriff auf die Variable leitet die
Laufzeitumgebung von VB.NET dann weiter auf das Objekt.
Das Ablegen der Speicheradresse eines Objekts in
einer Variable erfolgt mittels eines speziellen Zuweisungsoperators,
der Set- Anweisung:
Dim myUri as Uri
uri = New Uri
Der Zugriff auf das
Objekt erfolgt über den Variablenname. Auf Eigenschaften und
Methoden des Objektes kann mittels des . Operators zugegriffen
werden:
myUri.Host
1.3.7.2 System.Object - gemeinsamer Kern aller Referenztypen
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.
1.3.7.3 Wertetypen als Referenztypen: Boxing und
Unboxing- Konvertierung
Um auch Wertetypen im Bedarfsfall wie Objekte
behandeln zu können, stellt VB.NET einen komfortablen
Mechanismus bereit, genannt Boxing-Unboxing.
Wird ein Wertetyp in einem Objektkontext
aufgerufen, dann wird temporär auf dem Heap ein Objekt angelegt,
und der Wert des Wertetypen hineinkopiert. Dies wird als boxing
bezeichnet.
' zeichen ist ein Wertetyp und
Dim zeichen as Char = "A"C
' Im folgenden wird der Wertetyp in einem Objektkontext eingesetzt (zeichen.isDigit())
' Hier wird auf dem Heap ein Objekt erzeugt, dessen Kopie zeichen aufnimmt.
Dim aussage as String
aussage = IIF(zeichen.isDigit(), "Ziffer", "keine Ziffer")
' Wird ein Wertetyp als objekt- Referenz einem unterprogramm übergeben, dann ist er
' in eine Objektbox verpackt. Aus dieser muss er mittels eines Konvertierungsoperators
' wieder ausgepackt werden
Sub TueWas(oZeichen as Object)
' Unboxing- Konvertierung
Dim zeichen as Char = Ctype(oZeichen, Char)
...
End Sub
1.3.8 Typinformationen abrufen
1.3.8.1 is Operator
Der Is- Operator ergibt True, wenn zwei Referenzen
auf dasselbe Objekt verweisen:
If ref_a is ref_b
return True
End IF
1.3.8.2 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
1.3.8.3 GetType() Methode
Jedes Objekt erbt von der .net Wurzel
System.Object die Methode GetType. Diese liefert ein
Type- Objekt, welches alle Metainformationen zu einem Typ enthält.
1.3.8.4 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.
If strT1.GetType() = GetType(String) Then
Console.WriteLine("strT1 ist ein String")
End If
1.3.9 Blockstruktur, Sichtbarkeit und Lebensdauer von Variablen
1.3.9.1 Statische Variablen
In Sonderfällen kann es sinnvoll 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ähler variable 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
1.3.10 Unterprogramm- und Funktionsblöcke
Die grundlegende Blockstruktur erfordert den
Einschluss von Anweisungen in Blöcken.
Ein Unterprogrammblock ist eine benannte
Anweisungsliste. Über diesen Namen kann die Anweisungsliste
gestartet werden.
Eingerahmt wird der Unterprogrammblock wird mit
den Schlüsselwörtern Sub … End
Sub.
Sub PrintCurrentTime()
Dim dateTime As Date
dateTime = Now
Debug.Print ("Uhzeit " & dateTime.ToShortTimeString)
End Sub
Aufgerufen wird es über den Namen
PrintCurrentTime()
1.3.10.1 Implementierung des EVA- Prinzips mit Unterprogrammen
Ein
Grundprinzip der Programmierung ist die Eingabe - Verarbeitung -
Ausgabe, kurz EVA.
Ein
Beispiel dafür ist die Umrechnung von Polarkoordinaten
(Drehwinkel + Abstand) in kartesische Koordinaten (x,y). Das
rotierende Flughafenradar erfasst z.B. die Position eines Flugzeugs
in Polarkoordinaten. Die umgerechnete y Koordinate entspricht der
Flughöhe.
Die Umrechnung kann als VB.NET Unterprogramm
implementiert werden. Eingaben und Ausgaben werden dabei über
eine Parameterliste abgewickelt. In dieser werden alle Ein-
und Ausgaben deklariert analog den Variablendeklarationen.
Sub PolarToKartesian(r as Double, Phi as Double, ByRef x as Double, ByRef y as Double)
| |__________________________| |___________________________________|
| | |
Unterprogramm- Eingabeparameter Ausgabeparameter
name
Eingabeparameter sind
vergleichbar mit lokalen Variablen des Unterprogramms, die beim
Programmaufruf mit Daten aus dem Hauptprogramm initialisiert werden:
Dim x as Double : y as Double
PolarToKartesian(1591.2, 45.3, x, y) ' Programmaufruf
|_______| |___|
| |
Eingaben werden mit Daten aus Als Ausgaben werden Referenzen auf Variablen
Hauptprogramm initialisiert aus dem Hauptprogramm übergeben
Sind die
Ausgabeparametern von primitiven Typ (wie. z.B. Double, Integer, …)
dann müssen sie mit dem Schlüsselwort ByRef
gekennzeichnet werden, damit sie als
Referenzen (=Hauptspeicheradressen, Zeiger) übergeben werden. So
entspricht jede Zuweisung an einen Ausgabeparameter im Unterprogramm
einer Zuweisung der zugehörigen Variable im Hauptprogramm.
Sind
die Ausgabeparameter Objekte (= Referenztypen), dann ist
kein
ByRef erforderlich, da Objekte immer
als Referenzen übergeben werden.
Anbei
die vollständige implementierung der Koordinatenumrechnung:
'
Rechnet polare in kartesische Koordinaten um
Sub PolarToCartesian(r As Double, phi As Double, ByRef x As Double, ByRef y As Double)
Dim phiInRad As Double
phiInRad = (Application.Pi * phi) / 180#
x = r * Math.Cos(phiInRad)
y = r * Math.Sin(phiInRad)
End Sub
1.3.10.1.1 Allgemeine Definition eines Sub- Blocks
Sub <Funktionsname>(<Parameterliste>)
Anweisung 1
Anweisung 2
:
Anweisung n
return <Ausdruck>
End Sub
1.3.10.2 Selbstdefinierte Funktionen
Die Menge der vordefinierten VB.NET- Funktionen
kann mittels Funktionsblöcke erweitert werden. Funktionsblöcke
rahmen die Schlüsselwörter Function … End
Function ein.
Eingaben werden wie bei Unterprogrammen als
Parameterliste übergeben.
' Funktion, die eine römische Zahl auf einen Zahlenwert
' in arabischer Notation abbildet
Function RomToArabFunc(romNum As String) As Long
|_______________| |____|
| |
Argument Typ des Funktionswertes
Im Funktionsblock wird die Abbildungsvorschrift durch eine
Anweisungsliste implementiert. Der Funktionswert wird durch Zuweisen
an den Funktionsnamen festgelegt.
' Funktion, die eine römische Zahl auf einen Zahlenwert
' in arabischer Notation abbildet
Function RomToArabFunc(romNum As String) As Long
' Hilfsvariable anlegen, die Ergebnis der Konvertierung aufnimmt
Dim arabValue As Long
' Unterprogramm zur Konvertierung von römisch in
' arabische Zahlendarstellung aufrufen
RomToArab(romNum, arabValue)
' Funktionswert druch Zuweisen an Funktionsnamen festlegen
return arabValue
End Function
1.3.10.2.1 Allgemeine Definition eines Function- Block
Function <Funktionsname>(<Parameterliste>)
Anweisung 1
Anweisung 2
:
Anweisung n
return <Ausdruck>
End Function
1.3.11 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, dass einige Abschnitte 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, dass nach ihrer Ausführung das Programm an einer
beliebigen neuen Adresse fortgesetzt wird. Aufgrund dieser Wirkung
werden sie Sprunganweisungen genannt.
In
VB.NET sind die Sprunganweisungen in Form von bedingt ausführbaren,
oder bedingt wiederholbaren Blöcke.
1.3.11.1.1 Bedingt ausführbarer Anweisungsblock
Der
bedingt ausführbare Anweisungsblock 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 Anweisungsblock 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 Anweisungsblöcke 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
1.3.11.1.2 Bedingt wiederholbarer Anweisungsblock
Es handelt sich
hierbei um Anweisungsblöcke, 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 nicht
abweisende Schleife.
Bei
der abweisenden Schleife wird stets am Anfang des Anweisungsblockes
geprüft, ob die Bedingung für eine Ausführung erfüllt
ist. Wenn ja, dann wird der Anweisungsblock ausgeführt. Gilt die
Bedingung weiterhin, dann erfolgt eine wiederholte Ausführung
des Anweisungsblockes. Trifft die Bedingung nicht zu, dann wird der
Anweisungsblock übersprungen.
DO Bedingung
Anweisung 1
Anweisung 2
:
Anweisung n
Loop
Bei der nichtabweisenden Schleife wird die Bedingung erst am Ende des
Anweisungsblockes überprüft. Trifft sie zu, dann wird der
Anweisungsblock wiederholt. Sonst wird mit der nachfolgenden
Anweisung fortgesetzt.
Da die Bedingung erst am Ende des Abschnittes
überprüft wird, wird der Anweisungsblock immer mindestens
einmal ausgeführt.
DO
Anweisung 1
Anweisung 2
:
Anweisung n
Loop Bedingung
Sind Listen 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
Sollen alle Elemente einer Liste verarbeitet werden, dann kann der
For Each Anweisungsblock eingesetzt werden:
For Each el [as Type] in {Liste}
...
Next
1.3.12 Arrays
Zur Verarbeitung
tabellarischer Daten dienen in VB Arrays. Durch die Deklaration eines
Arrays werden im RAM n Speicherplätze zur Aufnahme von Werten
des Typs x reserviert.
Arrays
sind Referenztypen.
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 Index:
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
1.3.12.1 Initialisierung von Arrays
Dim primz() as Integer = {2, 3, 5, 7, 11}
1.3.12.2 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
1.3.12.3 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()
1.3.12.4 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)
1.3.12.5 Besuchen aller Einträge eines Arrays mittels foreach -
Schleife
For Each quadrat as Integer in quadrate)
Console.WriteLine(quadrat);
Next
1.3.12.6 Arrays sortieren
Dim planeten() as String = {"Merkur", "Venus", "Erde", "Mars", "Jupiter", "Saturn"}
Array.Sort(planeten);
1.3.13 Chars
1.3.13.1 Objektmodell von char
1.3.13.2 Chars
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.
1.3.13.2.1 Aufg.:
Programm, welches in einer Textbox eine
Teilmenge des Unicodes als Zeichencodetabelle ausgibt. Bsp:
Währungssymbole von 20A1 bis 20AF
Programm, welches alle Satzzeichen im Unicode
ausfiltert und anzeigt
1.3.14 Zeichenkettenverarbeitung (Strings)
1.3.14.1 Zeichenkettenoperatoren
Zeichenketten können mit den Operatoren + und
& zu einer neuen verbunden werden.
Dim txt as String
' verbinden mittels +
txt = "Betrag " + "99" + " Euro"
'verbinden mittels &. Zahlenwerte werden automatisch in Strings gewandelt
txt = "Betrag " & 99 & " Euro"
1.3.14.2 Teilstrings ausschneiden
Dim txt as String = "Anton,Berta,Cäsar"
Console.WriteLine(txt.Substring(6, 5))
1.3.14.3 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())
1.3.14.4 Startposition von Teilstrings bestimmen
Dim txt as String = "Anton,Berta,Cäsar"
Dim pos as Int32 = txt.IndexOf("Berta")
1.3.14.5 Einfügen in Strings
Dim txt as String = "Anton,Berta,Cäsar"
txt = txt.Insert(txt.IndexOf("Berta"), "Aladin,")
1.3.14.6 Auftrennen von Zeichenfolgen
Dim txt as String = "Anton,Berta,Cäsar";
Dim namen() as String = txt.Split(","c);
1.3.14.7 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))
1.3.14.8 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)
1.3.14.9 Aufgaben
Romzahlkonverter
Zählen der Buchstabenhäufigkeit in
gegebenen Texten
1.3.15 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.
1.3.16 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
1.3.16.1 Merkmale von Strukturen
Strukturen sind Wertetypen
Strukturen können Eigenschaften,
Methoden und Ereignisse besitzen
Es können parametrisierbare
Konstruktoren definiert werden.
Der parameterlose Konstruktor new() darf
nicht überschrieben werden.
Werden Strukturvariablen ohne New
definiert, dann werden die Felder der Struktur nicht
initialisiert
Werden
Strukturvariablen mit New definiert, dann erfolgen
Standardinitialisierungen der Felder
1.3.17 Einsprungadressen speichern (Delegates)
Jedes Unterprogramm, jede Funktion hat im
Arbeitsspeicher einen Startadresse, auch Einsprungadresse genannt.
Ein Unterprogramm startet, indem der Befehlszähler der CPU mit
dieser Einsprungadresse geladen wird.
Wie alle Daten
können auch Einsprungadressen gespeichert werden. Variablen, die
Einsprungadressen speichern, werden
Delegates genannt.
Der
Datentyp der Delegate- Variablen, die Einsprungadressen speichern,
schränkt auf Einsprungadressen von Unterprogramme mit einer fest
definierten Parameterliste und Rückgabewert ein. Die Variablen
bieten dazu ein Invoke- Methode an, über welche die
Einsprungadresse mit der passenden Parameterliste aufgerufen werden
kann.
Delegate-
Datentypen können selbst definiert werden mit dem Schlüsselwort
Delegate:
' Klasse erzeugen, in der eine Einsprungadresse einer binären Funktion abgelegt werden kann
Delegate Function DGBinär(a As Double, b As Double) As Double
Eine Delegate- Variable wird wie ein
Objekt angelegt, wobei die Einsprungadresse dem Konstruktor als
Parameter zu übergeben ist. Mittels AddressOf
Schlüsselwort wird dabei die
Einsprungadresse bestimmt zu einem gegeben Unterprogrammnamen:
Function Add(a As Double, b As Double) As Double
Return a + b
End Function
Function Subtract(a As Double, b As Double) As Double
Return a - b
End Function
Sub Main()
Dim op As DGBinär
' Adresse von Add mittels AddressOf- Operator ermitteln und im Delegate speichern
op = New DGBinär(AddressOf Add)
' Aufrufen eines Unterprogrammes über die Einsprungadresse
Dim Summe = op.Add(3, 9)
' Weitere Einsprungadressen können mit AddHandler hinzugefügt werden
AddHandler op, AddressOf Subtract
...
End Sub
1.3.18 Primzahlscanner imperativ implementieren
Teilaufgabe 1 wird durch folgende Befehlssequenz
gelöst (Pseudokode):
Primzahltest(In: Prüfling, Out: IstPrimzahl)
Dim Teiler = 2
Wiederhole bis Teiler = Prüfling / 2 + 1
Wenn Prüfling Mod Teiler = 0 dann
IstPrimzahl := false
Goto Ende Primzahltest
Sonst
Teiler := Teiler + 1
Ende Wenn, dann, sonst
Ende Wiederholung
IstPrimzahl = t
Ende Primzahltest
Teilaufgabe 2 implementiert folgende Befehlssequenz
Primzahlsuche(In: a, In: b, Out: ListePrimzahlen)
Dim Prüfling = a
Wiederhole bis Prüfling = b + 1
Dim IstPrimzahl
Primzahltest(In: Prüfling, Out: IstPrimzahl)
Wenn IstPrimzahl dann
ListePrimzahlen erweitern um Prüfling
Ende Wenn, dann
Prüfling = Prüfling + 1
Ende Wiederholung
Ende Primzahlsuche
1.4 Objektorientierte Programmierung in VB.NET
Die objektorientierte Programmierung ist eine
Erweiterung der klassischen, prozeduralen Programmierung um
Entwurfsmethoden und Ausdrucksmittel, durch welche
die Abbildung von Geschäftsprozessen auf
Programmstrukturen vereinfacht,
und der Programmcode transparenter wird.
Von zentraler Bedeutung sind dabei Objekte:
Definition
|
Objekt
|
Ein Objekt steht für ein konkretes Ding (z.B. Der rote
Ferrari von Fred Vollgas oder die Tabelle 1 im
Arbeitsblatt Umsätze).
Objekte besitzen einen inneren Zustand. Z.B. hat der rote
Ferrari von Fred Vollgas eine Geschwindigkeit, und die Zelle $A1
in Tabelle 1 des Wert 99. Der Zugriff auf den inneren Zustand
erfolgt über Eigenschaften.
Objekte kann man beeinflussen, indem man ihnen Nachrichten
sendet. Z.B. kann man den roten Ferrari in einer Simulation
auffordern, die Geschwindigkeit auf 100 km/h zu reduzieren, oder
dem Tabellenblatt mitteilen, den Hintergrund der Zelle $A1 rot zu
färben.
Zustandsänderungen in Objekten können Ereignisse
auslösen. Schert vor dem Ferrari urplötzlich aus der
rechten Spur eine grüne Ente aus, die den linken
Fahrstreifen mit Tempo 100 km/h blockiert, dann wird der Ferrari-
Fahrer wütend, und hupt (= löst das Ereignis Hupen)
aus. Durch dieses Ereignis können wiederum eine Reihe von
Nachrichten erzeugt werden, die an die umgebenden Objekte
gesendet werden (z.B. Nachricht Hupsignal an die grüne Ente
gerichtet).
|
1.4.1 Graphische Darstellung von Objekten mittels
Objektdiagramm
Die objektorientierte Sichtweise erleichtert die
die notwendige Formalisierung von Aufgaben- Problemstellungen bei der
Softwareentwicklung, indem sie eine 1:1 Abbildung der Realität
auf den Entwurf ermöglicht. 1:1 bedeutet nicht, das alle Details
der Realität im Entwurf nachgebildet werden. Der Entwurf
abstrahiert nach wie vor von der Realität, indem er die
Abbildung auf die für die Aufgabenstellung wesentlichen
Eigenschaften und Prozesse einschränkt. Jedoch ist weniger
Abstraktion notwendig als bei der rein Prozeduralen Programmierung,
da diese zusätzlich erfordert, alle Objekte in Mengen aus Daten
und diese manipulierende Prozeduren aufzulösen.
Objektdiagramm
|
Objekt
|
alternativ:
Objekt
|
+- Eigenschaft
|
+- M: Methode(Param1, Param2)
|
+- C: Collection
|
+- E: Event
|
|
Die Erweiterung zu objektorientierten
Sprache erfolgt in VB.NET im wesentlichen durch den Modul- und
Class- Block.
Module
|
Class
|
Alle Elemente sind implizit Shared
|
Zugriff auf die Elemente muss individuell
festgelegt werden
|
Im Unterschied zu den
Anweisungsblöcken der strukturierten Programmierung enthalten
Modul und Class- Block keine Anweisungen sondern stellen vielmehr
Container dar, die Functions, Sub's und Variablen aufnehmen, die zu
einem Aufgabenkomplex gehören/in einem sachlichen Zusammenhang
stehen.
1.4.2 Beispiel: Klasse Stoppuhr
Als Beispiel für eine Klassendeklaration und
Objekte diene die Klasse Stoppuhr.
Mit einem Stoppuhr- Objekt kann in einem Programm die Rechenzeit für
aufwendige Berechnungen gemessen werden.
Beispielanwendung:
<TestMethod()> Public Sub StoppuhrTest()
' Stoppuhrobjekt anlegen
Dim uhr1 As New VB.OO.Klassenlib.Stoppuhr
With uhr1
' Zeitmessung starten
.Start()
' Simulation einer aufwendigen Berechnung
System.Threading.Thread.Sleep(ZeitLimit)
' Zeitmessung stoppen
.Stopp()
' Zeitmessung auswerten
Assert.IsTrue(.ZeitInMs > ZeitLimit - 1)
End With
End Sub
1.4.3 Innerer Zustand
Objekte können wie Variablen Informationen
speichern. Dieser objekt- interne Informationsspeicher wird als
Innerer Zustand bezeichnet.
Implementiert
wird der innere Zustand durch Variablen, auch Felder genannt, die zu
Beginn eines Klassenmoduls mittels
Dim- Anweisungen
zu
vereinbaren sind:
' Innere Zustand der Stoppuhrklasse:
' Zeitpunkte beim Start und Stop auf dem System.DateTime- Zeitstrahl
Dim _TicksBeimStart As Long
Dim _TicksBeimStopp As Long
' Name der Stoppuhr
Dim _Name As String
1.4.4 Methoden
Methoden sind für
den externen Zugriff freigegebene Prozeduren (Sub's) oder Funktionen
(Function's). Aus der Perspektive der Objektorientierung sind
Methoden Nachrichten, die an ein Objekt gesendet werden. Diese
Nachrichten beeinflussen den inneren Zustand eines Objektes.
In einer etwas praktischeren Sichtweise können
wir Methoden als Operationen betrachten, die abhängig vom
inneren Zustand des Objektes sind.
In einem Klassenmodul werden Methoden als
öffentliche Sub's oder Function's definiert:
' Methode = Nachricht an Stoppuhr, Zeitmessung zu starten
Sub Start()
Reset()
End Sub
' Methode = Nachricht an Stoppuhr, Zeitmessung zu stoppen
Sub Stopp()
_TicksBeimStopp = DateTime.Now.Ticks
' Wenn das definierte Zeitlimit überschritten wurde, feuert ein Ereignis
If ZeitlimitInMs > -1.0 And ZeitInMs > ZeitlimitInMs Then
RaiseEvent ZeitlimitUeberschritten(Name)
End If
End Sub
' Methode = Nachricht an StoppUhr, inneren Zustand zurückzusetzen
Sub Reset()
_TicksBeimStart = DateTime.Now.Ticks
_TicksBeimStopp = _TicksBeimStart
End Sub
1.4.5 Eigenschaften
Eigenschaften sind die Schnittstellen zum inneren
Zustand eines Objektes. Sie werden in VB.NET durch benannte Paare von
Methoden implementiert, die in einem Property-
Block eingeschlossen sind. Sie ermöglichen die
Manipulation des inneren Zustandes.
Property <Name der Eigenschaft> As <Datentyp>
' Der Getter
Get
Return <Ausdruck, der auf inneren Zustand zugreift>
End Get
' Der Setter
Set(value As <Datentyp>)
' Zugriff auf inneren Zustand
End Set
End Property
Im allgemeinen ist der direkte
Zugriff auf die Felder verboten, welche den inneren Zustand eines
Objektes implementieren. In VB.NET kann man jedoch Felder Public
deklarieren, wodurch der
direkten Zugriff auf den inneren Zustand möglich wird. Das
verletzt jedoch die Prinzipien der objektorientierten Programmierung
und kann als Relikt aus der "Computersteinzeit" betrachtet
werden !
Eine Methode des Paars wird Setter genannt.
Sie wird mit dem Schlüsselwort Set markiert
und ermöglicht einen Schreibzugriff auf den inneren Zustand:
' Der Setter
Set(value As <Datentyp>)
' Zugriff auf inneren Zustand
End Set
Aufgerufen wird der Setter, wenn
man der Eigenschaft einen neuen Wert zuweist:
Objekt_X.MyProp =
Neuer Wert
Die andere Methode
ist der Getter. Er ermöglicht einen Lesezugriff auf den
inneren Zustand:
' Der Getter
Get
Return <Ausdruck, der auf inneren Zustand zugreift>
End Get
Aufgerufen wird der
Getter, wenn man den Wert aus der Eigenschaft ausliest:
Dim meineVariable as Integer
meineVariable = Objekt_X.MyProp
1.4.5.1 Beispiele für Eigenschften in der Stoppuhrklasse:
' Primitive Eigenschaft, die einen inneren Zustand liest und schreibt, der vom
' VB- Compiler implizit angelegt wird: Grenzwert für ZeitInMs, unterhalb dem bei Stopp kein
' ZeitlimitUeberschritten- Event gefeuert wird.
Property ZeitlimitInMs As Double
' Name der Stoppuhr (nur lesbar)
ReadOnly Property Name As String
Get
Return _Name
End Get
End Property
' Lese- und beschreibbare Eigenschaft: ermölicht das Lesen und Schreiben
' des Zeitlimits in Sekunden
Property ZeitlimitInSec As Double
Get
Return ZeitlimitInMs / 1000.0
End Get
Set(value As Double)
ZeitlimitInMs = value * 1000.0
End Set
End Property
1.4.6 Ereignisse
Wenn ein Objekt einen
besonderen Zustand annimmt, kann es abhängig von der
Aufgabenstellung erforderlich sein, andere Objekte darüber zu
informieren. Diese Situation wird Ereignis genannt.
Die Stoppuhr kann über die Eigenschaft
ZeitlimitInMs so konfiguriert
werden, dass sie ein ein Ereignis "feuert", wenn
eine Einstellbare Zeitspanne in der Messung überschritten wurde.
Das Feuern erfolgt mit RaiseEvent in
der Stopp- Methode:
Sub Stopp()
_TicksBeimStopp = DateTime.Now.Ticks
' Wenn das definierte Zeitlimit überschritten wurde, feuert ein Ereignis
If ZeitlimitInMs > -1.0 And ZeitInMs > ZeitlimitInMs Then
RaiseEvent ZeitlimitUeberschritten(Name)
End If
End Sub
Ein "Ereignis feuern" kann man sich wie einen
Methodenaufruf vorstellen. Jedoch ist die Methode nicht fest beim
Implementieren der Stoppuhr definiert worden. Stattdessen kann die
Methode nachträglich an das Ereignis "gebunden" werden
mit dem AddHandler Befehl.
Man nennt die an das Ereignis gebundenen Methoden auch Eventhandler.
' Eventhandler für Zeitmessung
Sub ZeitlimitUebrschrittenEventHandler(Uhrname As String)
hatZeitlimitUeberschritten = True
End Sub
Const ZeitLimit As Integer = 500
Dim hatZeitlimitUeberschritten As Boolean = False
<TestMethod()> Public Sub StoppuhrTest()
' Stoppuhrobjekt anlegen
Dim uhr1 As New VB.OO.Klassenlib.Stoppuhr
With uhr1
Dim hatZeitlimitUeberschritten2 As Boolean = False
' Eventhandler registrieren
AddHandler .ZeitlimitUeberschritten, AddressOf ZeitlimitUebrschrittenEventHandler
AddHandler .ZeitlimitUeberschritten, Sub(Name) hatZeitlimitUeberschritten2 = True
' Zeitlimit konfigurieren
.ZeitlimitInMs = ZeitLimit - 1
' Zeitmessung starten
.Start()
' Simulation einer aufwendigen Berechnung
System.Threading.Thread.Sleep(ZeitLimit)
' Zeitmessung beenden
.Stopp()
' Zeitmessung auswerten
Assert.IsTrue(hatZeitlimitUeberschritten And hatZeitlimitUeberschritten2)
End With
End Sub
Aus technischer Sicht ist ein Ereignis ein Speicherort, an dem andere
Objekte Einsprungadressen von Methoden (Eventhandler) hinterlegen,
die starten sollen, wenn das Ereignis eintritt bzw. "feuert".
1.4.7 Primzahlscanner objektorientiert implementieren
Teilaufgabe 1 wird durch Zahlenobjekte gelöst,
die eine IstPrimzahl- Methode besitzen. Wir senden bildlich
gesprochen dem Zahlenobjekt eine Anfrage, ob es eine Primzahl ist
oder nicht, indem wir seine IstPrimzahl- Methode aufrufen. Gibt diese
true zurück, dann ist das Zahlenobjekt eine Primzahl, sonst
nicht.
Teilaufgabe
2 wird durch zwei Objekte gelöst. Das eine (Zahlenbereich)
erzeugt für vorgegebene Grenzen eine Liste aus Zahlenobjekten,
die alle Zahlen innerhalb der Grenzen als Zahlenobjekte umfasst.
Das andere (Primzahlscanner) filtert die Liste,
indem es jeden Eintrag über die IstPrimzahl- Methode befragt, ob
es eine Primzahl ist. Objekte von Primzahlen werden in die
Ergebnisliste kopiert
1.5 Funktionale Programmierung in VB.NET
Die Mathematiker entwickelten in Jahrhunderten
eine eigene Sprache: die Sprache der Formeln und Funktionen. Diese
Sprache besteht aus Operatoren wie z.B. + und *, Zahlendarstellungen
und Symbolen für Konstanten (z.B. π)
und Veränderliche
(z.B. x, D). Beispiele sind die Formel zur Berechnung des
Kreisumfanges:
U = π * D
1.5.1 Funktionen
Allgemeiner kann man den Zusammenhang zwischen
Durchmesser D eines Kreises und seinem Umfang U durch eine Funktion
darstellen:
f(D): D → π * D
Den Ausdruck kann man lesen als: die Funktion f(D)
ordnet jedem Durchmesser D einen Kreisumfang f(D) =
π
* D zu. Diese Darstellung wurde in den 1930-er Jahren zu einem
präzisen Formalismus ausgearbeitet (Alonzo Church, Stephen
Kleene: Lambda- Kalkül), welcher die Grundlage für die
Familie der
funktionalen
Programmiersprachen
wie z.B. LISP oder F# bildet.
Während
die Mathematiker Funktionen gerne mit einem einzigen Buchstaben
bezeichnen, und dabei auch noch auf das griechische Alphabet
zugreifen, bevorzugen die Programmierer lieber sprechende Namen wie:
Kreisumfang(D):
D → π * D
1.5.1.1 Funktionen
in VB.NET
Eine
Funktion wird in VB.NET durch einen Funktionsblock dargestellt, der
mit dem Schlüsselwort
Function
beginnt.
Diesem folgt eine Parameterliste, die alle Veränderlichen
auflistet, von denen der Funktionswert abhängt. Im
Funktionsblock wird der Funktionswert berechnet und zurückgegeben.
Beispielsweise kann die Kreisumfangsfunktion in VB.NET wie folgt
dargestellt werden:
' VB.NET
Function Kreisumfang(D)
Return Math.Pi * D
End Function
Das
return
entspricht
dabei dem Abbildungspfeil → in der mathematischen Darstellung
Kreisumfang(D): D →
π
* D.
Die Funktion kann nun angewendet werden, indem sie
mit einem Argument aufgerufen wird:
' Der Umfang eines Kreises mit 250 cm Durchmesser wird berechnet
Kreisumfang(250)
1.5.1.2 Übungen
Implementieren
Sie eine Funktion in VB.NET, die einen gemessene Länge in cm auf
eine Länge in m abbildet:
CmInMeter(x): x → x*0,01
1.5.1.3 Mathematische Funktionen
Die wichtigsten mathematischen Funktionen sind im
Math- Objekt des Namespace System enthalten.
1.5.1.4 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.
1.5.1.5 Benannte Parameter
Parameterlisten von Funktionen/Unterprogrammen
können lang werden. Zudem müssen beim Aufruf die
Reihenfolge der Parameter beachtet werden. Ein Funktionsaufruf
erfordert in diesem Fall immer ein Studium der Dokumentationen.
Mittels benannter Parameter kann die Situation
entschärft werden. Die Kenntnis der Parameterreihenfolge ist
nicht mehr erforderlich, weil die Werte Parameternamen beim Aufruf
beigestellt werden. Die richtige Platzierung der Werte in der
ursprünglichen Parameterliste erfolgt nun durch den Compiler.
' Funktion mit komplexer Parameterliste
Public Function CreatePlanet(Name As String, _
DiameterInKm As Double, _
GravityInMeterPerSec As Double) As Planet
Return New Planet With { _
.Name = Name, _
.DiameterInKm = DiameterInKm, _
.GravityInMeterPerSec = GravityInMeterPerSec _
}
End Function
' Aufruf über benannte Parameter
Dim Erde = CreatePlanet(Name:="Erde", _
DiameterInKm:=12756, _
GravityInMeterPerSec:=9.81)
1.5.1.6 Parameterarrays
Funktionen, die Listen von Werten eines festen
Typs abbilden, wird durch Parameterarrays der Einsatz erleichetert:
Beispiel:
Function Sum(ParamArray summanden( ) As Double)
Dim i As Integer, summe As Double
For i = 0 To summanden.GetUpperBound(0)
summe += summanden(i)
Next
Return summe
End Function
Gewöhnlich muss zuerst die Liste z.B. durch ein Array
implementiert, und dieses dann an die Listenfunktion übergeben
werden:
Dim liste() = {3.0, 5.0, 7.0, 11.0, 13.0}
Dim SumListe = Ctx.Sum(liste)
Dank ParamArray- Modifikator kann die Liste auch im Funktionsaufruf
erzeugt werden, wodurch eine Zeile Code entfällt, und die Syntax
des Sum- Funktionsaufrufes sehr anschaulich wird:
' Dank ParamArray- Zusatz in der Parameterliste wird die Liste 1, 2, ...
' vom Compiler automatisch in ein Array verpackt
Dim summeAus3 = Ctx.Sum(1, 2, 3)
Dim summeAus6 = Ctx.Sum(1, 2, 3, 4, 5, 6)
1.5.1.7 Delegate (Funktionszeiger)
Komponenten 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 muss der Komponente 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.
1.5.1.8 Deklaration eines Delegate
Jeder Delegate muss vor seiner Verwendung
deklariert werden:
[Zugriffsmodifikator] Delegate Methodendeklaration
z.B.:
' Klasse für Einsprungadressen von Funktionen mit zwei Integerparametern
' und einem Interger- Rückgabewert
Delegate Function DgBinOp(a As Double, b As Double) As Double
:
Function Add(a As Double, b As Double) As Double
Return a + b
End Function
:
' Einsprungadresse einer Funktion speichern
Dim op As New DgBinOp(AddressOf Add)
Debug.WriteLine("2 + 5 = " & op(2, 5))
1.5.1.9 Lambda-
Ausdrücke
Der
Begriff Lambda Ausdruck wurde in einem Formalismus der Mathematiker
Alonzo Church und Stephe Kleene in den 1930 Jahren geprägt
(Lambda
Kalkül
). Dieser Kalkül wird auch
als der Urahn der funktionalen Programmierung betrachtet.
Ein
Lambda- Ausdruck ist eine Funktionsdeklaration in Form eines
Ausdrucks innerhalb eines Funktions- oder Programmblockes.
Delegate Function DgBinOp(a As Double, b As Double) As Double
' Einsprungadresse eines Lambda- Ausdruckes
' Der Lambdaausdruck ist eine inline definierte anonyme Funktion
op = New DgBinOp(Function(a, b)
Return a * b
End Function)
Debug.WriteLine("2 * 5 = " & op(2, 5))
Der
Sinn von Lambdaausdrücken erschließt sich, wenn diese z.B.
über Parameterlisten an Unterprogramme oder Funktionen übergeben
werden, um diese "funktional" zu parametrieren:
Dim zahlen() As Integer = {3, 55, 78, 32, 94, 99, 103, 108}
' Formulieren kurz und knackig mit Lambdaausdruck
alleDurch2TeilbarenAlsListe = zahlen.Where(Function(z) z Mod 2 = 0).ToArray()
1.5.2 Fallunterscheidungen
Neben
den Ausdrücken wie
π
* D
können
die Abbilder von Funktionen auch durch Fallunterscheidungen definiert
werden. Z.B. kann die Funktion, die jeder Zahl ihren absoluten Betrag
zuordnet, wie folgt beschrieben werden:
Fallunterscheidungen
-z z < 0
|z| = Abs(z): z → 0 für z = 0
z z > 0
z.B. Abs(-5) = 5, Abs(5) = 5, Abs(0) = 0
1.5.2.1 Fallunterscheidungen
in VB.NET
Die
Fallunterscheidung wird mit dem IF … THEN- Block
implementiert. Zwischen IF … THEN wird die Bedingung
definiert. Wenn sie zur Laufzeit erfüllt wird, dann werden die
im Block definierten Berechnungen ausgeführt, sonst nicht.
' VB.NET
Public Function ABS(z)
If z < 0 Then
Return -z
ElseIf z > 0 Then
Return z
Else
Return 0
End If
End Function
1.5.2.2 Übung
Implementieren
Sie eine Funktion in VB.NET mit zwei Parametern, die den Preis eines
Wirtschaftsgutes und der Warengruppe, zu der es gehört, auf
einen Mehrwertsteuerbetrag abbildet:
Mehrwertsteuerberechnung
preis * 0,07 wg = "ermäßigt"
MwSt(preis, wg): (preis, wg) → für
preis * 0,19 wg = "normal"
1.5.3 Funktionen
hintereinander schalten
In
der Mathematik kann man mittels Funktionen eine Menge {x} auf eine
Menge {y}, und die Menge {y} wiederum auf die Menge {z} abbilden.
Formal wird dies wie folgt beschrieben:
Wenn
f1(x): x → y und f2(y): y → z dann ist
f2(f1(x))
: x →
z
Damit
kann man z.B. die Berechnungen des Kreisumfanges an Durchmesser
anpassen, die in verschiedenen Maßeinheiten gemessen wurden:
Funktionen hintereinanderschalten
MillimeterInMeter(x): x → x * 0,001
CentimeterInMeter(x): x → x * 0,01
Kreisumfang(D): D → π * D
D D
/--------+--------\ /----+----\
Kreisumfang(MillimeterInMeter(x)): x → π * (x * 0,001)
Kreisumfang(CentimeterInMeter(x)): x → π * (x * 0,01)
z.B. Kreisumfang(CentimeterInMeter(100)) = 3,142..., Kreisumfang(MillimeterInMeter(100)) = 0,3142...
1.5.3.1 Funktionen
hintereinanderschalten in VB.NET
Die
Syntax der Hintereinanderschaltung ist identisch mit der bereits
eingeführten allgemeinen Syntax.
Dim UmfangInMeter = Kreisumfang(MillimeterInMeter(x))
1.5.3.2 Übung
Zu
einem Netto- Preis soll erst der Brutto- Preis (inkl. MwSt) und dann
der Skonto (3%) berechnet werden. Implementieren Sie die Stufenweise
Preisermittlung durch Hintereinanderschalten von Funktionen.
1.5.4 Rekursion
Mathematiker
sind findige Menschen. Sie hatten schnell erkannt, dass mit der
Hintereinaderschaltung von Funktionen ein mächtiges Instrument
bereitsteht, mit dem man sich weit in die Tiefen mathematischer
Probleme vorwagen kann. Eine besondere Form ist die Rekursion. Auf
dieser basieren die funktionalen Beschreibungen vieler mächtiger
Algorithmen.
Z.B.
soll ein Vertreter 3 Kunden nacheinander besuchen, wobei die gewählte
Reihenfolge die mit der kleinsten Gesamtstrecke ist (Problem der
Rundreise mit minimaler Streckenlänge).
Die
Lösung benötigt zunächst einen Graphen, dessen Knoten
den Startpunkt und die Kunden darstellen, und dessen Kanten die
Entfernungen zwischen den Knoten angeben. Dann sind für alle
möglichen Reihenfolgen der Besuche die Summen der Wege zu
berechnen. Am Ende ist die Reihenfolge mit der kleinsten Summe als
Lösung auszuwählen. Folgendes Bild veranschaulicht das
Vorgehen:
Wie
viele Reihenfolgen über dem Graphen, und wie viele Summen damit
gebildet werden müssen, gibt die aus der Kombinatorik bekannte
Fakultät-
Funktion
an:
Fakultät berechnen
1 n = 0
N!(n): n → für
n*N!(n-1) n > 0
Die
Funktion wird mittels einer Fallunterscheidung definiert, wobei für
den Fall n > 0 der Funktionswert durch einen Term beschrieben
wird, der N! wiederum enthält. Man erhält eine Lösung,
indem man auf eine Lösung für den Vorgänger
zurückgreift. Diese Art von Funktionsdefinition wird Rekursion
genannt.
Aufgelöst
wird die Rekursion von N! z.B. für n = 3 wie folgt:
N!(3) = 3*N!(2) = 3*2*N!(1) = 3*2*1*N!(0) = 3*2*1*1 = 6
Die
Fakultät wächst mit n extrem. Die exakte Lösung des
Rundreiseproblem für große n praktisch unmöglich.
1.5.4.1 Rekursion
in VB.NET
Public Function Fact(n)
If n = 0 Then
Return 1
Else
Return n * Fact(n - 1)
End If
End Function
1.5.4.2 Übung
Implementiere
eine rekursive Funktion, die eine gegebene Zahlenpaar
Basis,
Exponent
die
Potenz berechnet wie folgt:
Potenz(Basis,
Exponent): (Basis, Exponent) → Basis
Exponent
Beachte
dabei die Beziehung: b
e
=
b * b
e-1
=
b * b * b
e-2
1.5.5 Listenverarbeitung
In
den Naturwissenschaften werden oft mehrere Messwerte einer
Beobachtung zugeordnet werden. Es entstehen Paare von Messwerten. Ein
Beispiel ist die Beobachtung eines beschleunigenden Fahrzeugs. Dabei
wird in festen Zeitabständen die Momentangeschwindigkeit
notiert.
Messung: {(v, t)} := {(1 m/s, 1s), (2 m/s, 2s), …, (12 m/s, 5s)}
Ein
anderes Beispiel sind die möglichen Folgen, in denen die Kunden
A, B, C besucht werden (siehe vorausgegangener Abschnitt)
Besuchsreihenfolgen: {(K1, K2, K3)} := {(A, B, C), (B, A, C), (B, C, A), (C, B, A), (C, A, B), (A, C, B)}
Die
Permutationen über der dreielementigen Menge {A, B, C} bilden
hier alle möglichen Reihenfolgen. Jede Reihenfolge wird als ein
Triple dargestellt.
Paare,
Tripel oder allgemein Tupel sind spezielle Formen von Listen.
Liste := (e1, e2, …., eN)
Mit
Listenverarbeitung werden allgemein Funktionen bezeichnet, die Listen
auf Listen oder Listen auf skalare Werte abbilden
Listenverarbeitung := {f mit f(Liste X) : Liste X → Liste Y oder f(Liste X): Liste X → Y}
1.5.5.1 Listenverarbeitung
in VB.NET
Anstelle
runder Klammern werden in VB.NET für die Listenbegrenzer
geschweifte Klammern verwendet. Auch die Definition eines
Listenbezeichners verwendet statt := das Symbolpaar
Dim
und
=.
Dim Liste = { e1, e2, …, eN}
Folgenden
Tabelle definiert die grundlegenden Funktionen der Listenverarbeitung
Name
|
Beispiel
|
Beschreibung
|
{...}
|
Dim ListeX = {1,2,3}
|
Erzeugt eine Liste mit den angegebenen
Elementen.
|
{…}(i)
|
2 = {1,2,3}(1)
|
Liefert den Wert des i-ten Listenelementes
|
Count({…})
|
3 = Count({1,2,3})
|
Gibt die Anzahl der Elemente in einer Liste
zurück
|
First({…})
|
1 = First({1,2,3})
|
Gibt das erste Element einer Liste zurück
|
Last({…})
|
3 = Last({1,2,3})
|
Gibt das letzte Element einer Liste zurück.
|
Reverse({…})
|
{3,2,1} =
Reverse({1,2,3})
|
Liefert eine Liste mit allen Elemente der
Eingangsliste in umgekehrter Reihenfolge
|
Take({…}, i)
|
{1,2} = Take({1,2,3,4},
2)
|
Liefert eine Liste mit den ersten i Elemente
der ursprünglichen Liste
|
Skip({…}, i)
|
{3,4} = Take({1,2,3,4},
2)
|
Liefert eine Liste mit den ersten i Elemente
der ursprünglichen Liste
|
Concat({…},{…})
|
{1,2,3,4,5} =
Concat({1,2,3},{4,5})
|
Verkettet zwei Listen zu einer neuen Liste
|
ForEach({…}, f)
|
{1,4,9} =
ForEach({1,2,3}, Function(x) x*x)
|
Liefert zu einer Liste die Liste mit den
Funktionswerten f(x) für jedes x aus der eingegebenen Liste.
|
Im
Folgenden Beispiele für einfache Funktionen zur
Listenverarbeitung. Wie man sieht, wird die Rekursion intensiv
genutzt:
Bildet
die Summe aller Werte in einer Liste
Summenbildung
Summe({a1, a2, …, aN}): {a1, a2, …, aN} → a1 + a2 + … + aN
Function Summe(liste)
If Count(liste) = 0 Then
Return 0
ElseIf Count(liste) = 1 Then
Return liste(0)
Else
Return First(liste) + Summe(Skip(liste, 1))
End If
End Function
Sucht
das Minimum in einer Liste:
Minima finden
Min({…}): {…} → min mit min
ϵ
{…} & Für alle x
ϵ
{…} gilt: min <= x
Function Min(list)
If Count(List) = 0 Then
Throw New Exception()
ElseIf Count(List) = 1 Then
Return List(0)
ElseIf First(list) < Min(Skip(list, 1)) Then
Return First(list)
Else
Return Min(Skip(list, 1))
End If
End Function
Erzeugt
eine Liste mit den Werten 1-N:
Liste mit Werten erzeugen
PTupelStart(n): n → {1,2, …,n}
Function PTupelStart(n)
If n = 1 Then
Return {1}
Else
Return Concat(PTupelStart(n - 1), {n})
End If
End Function
Prüft
zwei Listen auf vollständige Übereinstimmung:
Gleichheit von Listen prüfen
Equal({a1,a2,…,aN}, {b1,b2,…,bM}): ({a1, a2, …, aN}, {b1, b2, …, bM}) → true für
Count({a1,a2,…,aN}) = Count({b1, b2, …, bM}) und
a1 = b1, a2 = b2, …, aN = bM
Function Equal(listA, listB)
If Count(listA) <> Count(listB) Then
' Ungleich lange Listen können nie gleich sein
Return False
ElseIf Count(listA) > 0 Then
' Rückführung auf die Prüfung, das der Anfang gleich ist und der Rest auch
Return First(listA) = First(listB) And Equal(Skip(listA, 1), Skip(listB, 1))
Else
' Zwei leere Listen sind immer gleich
Return True
End If
End Function
1.5.6 Primzahlscanner
funktional realisieren
Teilaufgabe
1 kann z.B. durch folgende Funktion dargestellt werden (Pseudokode):
IstPrimzahl(z): z → z Mod 2 <> 0 AND TesteWeiterAufPrimzahl(z, 3)
TesteWeiterAufPrimzahl(z, t): z,t → z Mod t <> 0 AND
Wenn t = z/2
dann true
sonst TesteWeiterAufPrimzahl(z, t + 1)
Wir
setzen die Lösung in VB.NET um:
Function IstPrimzahl(z As Long) As Boolean
Return TesteAufTeiler(z, 2)
End Function
Private Function TesteAufTeiler(ByRef z As Long, KandidatTeiler As Long) As Boolean
If KandidatTeiler >= z \ 2 + 1 Then
Return True
Else
Return z Mod KandidatTeiler <> 0 And TesteAufTeiler(z, KandidatTeiler + 1)
End If
End Function
Die
funktionale Lösung ist eine, dem Mathematiker geläufige
Form und besticht durch ihre Kürze. Nicht- Mathematikern haben
aber in der Regel große Probleme, die Wirkung dieser
funktionalen Ausdrücke, die auf Rekursion beruht, zu verstehen.
Auch
für Teilaufgabe 2 gibt es eine Funktionale Lösung
(Pseudokode):
AllePrimzahlenIn(a, b): a, b → Alle x in [a, b] für die gilt: IstPrimzahl(x)
Die Funktion bildet dabei das Paar a,b auf eine Menge mit allen
Primzahlen zwischen a und b ab.
In VB.NET kann die
Lösung mittels LINQ To Objects ab .NET 3.5 direkt umgesetzt
werden
1.6 Erweiterte Grundlagen
1.6.1 Modifikatoren
Modifikatoren beeinflussen das Laufzeitverhalten
einer Variable. So wird durch einen Const- Modifikator
das Ändern des Inhaltes einer Varaible zur Laufzeit verboten.
Mit dem Static- Modifikator
wird die Platzierung der Variable in einem globalen Segement
erreicht, wodurch sie mit Programmstart erzeugt wird und für die
gesamte Dauer des Programms erhalten bleibt.
Modifikator
|
Beschreibung
|
Anwendbar auf
|
Const
|
Inhalt der Variable ist für die gesamte
Ausführungszeit unveränderlich
|
Modulebene
|
ReadOnly
|
Nur in der Dekalration oder im Konstruktor
einr Klasse kann ein Wert an einen ReadOnly zugewiesen werden
|
Modulebene
|
Static
|
Definiert eine lokale Variable innerhalb einer
Prozedur oder Funktion, die für den gesamten Zeitraum des
Programmablaufes gültig, aber nur innerhalb der Methode
sichtbar ist.
|
Prozedurebene
|
Shared
|
Definiert einen Klassenmember. Der Member ist
unabhängig von Instanzen der Klasse. Entspricht den
Modulvariablen oder Prozeduren von VB6
|
Modulebene
|
1.6.2 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.
Zugriffsmodifikator
|
Beschreibung
|
Public
|
Öffentlicher Member. Auf ihn kann aus
jeder Ebene zugegriffen werden.
|
Private
|
Kennzeichnet ein Implementierungsdetail. Ist
außerhalb des Klassen oder Modulblockes, in dem er
definiert wurde, nicht sichtbar
|
Protected
|
Kennzeichnet ein Implementierungsdetail einer
Klassenhierarchie. Ist außerhalb der Klassenblöcke der
Klassenhierarchie nicht sichtbar
|
Friend
|
Zugriff nur innerhalb der Assembly möglich,
in der der Member deklariert wurde
|
1.6.3 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
1.6.3.1 Aufgaben
Entwickeln
Sie eine Klasse CTypeBrowser, welche die Methode info(object)
implementiert, die zu einem
gegebenen Objekt alle Felder und Methoden auflistet.
1.6.4 Elementare Ein/Ausgabe
Beispiel:
Dim preis As Dezimal = 99.45
Console.WriteLine("Preis: {0,10:########.##}€", preis)
1.6.4.1 Formatzeichenfolgen
Über Formatzeichenfolgen wird abhängig
vom Datentyp die Darstellung eines Wertes als String gesteuert. Es
gibt Formatzeichenfolgen für:
nummersiche Typen
Datumstypen
Aufzählungstypen
1.6.4.2 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:
Bezeichner
|
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
1.6.4.3 Formatzeichenfolgen für Datumstypen
Bezeichner
|
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
|
1.6.4.4 Formatzeichenfolgen für Aufzählungstypen
Bezeichner
|
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
|
1.6.4.5 ToString und Formatierung
1.6.4.6 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))
1.6.4.7 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.
1.6.4.8 Array mit selbstdefinierten Typen Sortieren
enum ELaenge {mm, cm, dm, m, km};
struct Laenge : IComparer
{
public float wert;
public enumLaengenEinheiten einheit;
public int Compare(object obj1, object obj2)
{
Laenge l1 = (Laenge)obj1;
Laenge l2 = (Laenge)obj2;
// alles in mm umrechnen
float il1 = tomm(l1), il2 = tomm(l2);
if (il1 == il2)
return 0;
else if (il1 < il2)
return -1;
else
return 1;
}
float tomm(Laenge l)
{
switch (l.einheit) {
case ELaenge.mm:
return l.wert;
case ELaenge.cm:
return l.wert * 10;
case ELaenge.dm:
return l.wert * 100;
case ELaenge.m:
return l.wert * 1000;
case ELaenge.km:
return l.wert * 1000000;
}
return -1;
}
}
// In Main
Laenge[] fahrten = new Laenge[3];
fahrten[0].einheit = ELaenge.mm;
fahrten[0].wert = 100000;
fahrten[1].einheit = ELaenge.cm;
fahrten[1].wert = 3000;
fahrten[2].einheit = ELaenge.km;
fahrten[2].wert = 0.99F;
Array.Sort(fahrten, fahrten[0]);
foreach (Laenge fahrt in fahrten)
{
Console.WriteLine("{0} {1}", fahrt.wert, fahrt.einheit.ToString());
}
1.6.4.9 Aufg.:
Min/Max- Suche,
Sortieren
Messwerterfassung (akt. Wert, dyn.
Mittelwert)