Visual Basic .NET: Funktionen

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Oft gibt es in einem Programm wiederkehrende Aufgaben, für die man denselben Code verwenden kann. Stellen Sie sich einen Webbrowser vor, der immer wieder Dateien aus dem Internet herunterladen muss, seien es Webseiten, Bilder oder Archive. Intutitiv würde man den entsprechenden Code immer wieder verwenden. Nun stellen Sie sich vor, Sie haben im Download-Code einen Fehler gefunden. Nun müssten Sie jedes Vorkommnis des Fehlers suchen und ausmerzen, was anstrengend und langweilig ist und eine hohe Gefahr von Fehlern mit sich bringt, etwa dass Sie ein Vorkommen übersehen oder sich vertippen.

Zum Glück bietet Visual Basic eine Möglichkeit, wiederkehrende Aufgaben nur einmal zu definieren und eine Schnittstelle bereitzustellen, die unendlich oft wiederverwendet werden kann, um diese Aufgabe anhand des vorhandenen Codes zu lösen. Diese Möglichkeit heißt Funktion. Schauen Sie sich das folgende Beispiel an. Ihnen wird auffallen, dass jetzt wieder der komplette Code notiert wird, da wir nicht mehr nur Main() bearbeiten.

Crystal Clear app terminal.png Code:  

Module Beispiel
     Sub Main()
         Console.Write("Geben Sie eine Zahl ein: ")
         Dim a As Integer = Console.ReadLine()
         Do
             a = 2 * a
             If a = 4 Then End
         Loop Until a > 100
         End
     End Sub
 End Module

Probieren Sie einmal verschiedene Werte wie 5 oder 6 aus. (In solchen Fällen ist es oft eine gute Idee, sich vorher zu überlegen, was bei welchen Werten von a passieren müsste.) Beachten Sie, dass in diesem Fall keine Gültigkeitsprüfung für den eingegebenen Wert implementiert werde. Das heißt, dass nicht geprüft wird, ob überhaupt eine positive Zahl eingegeben wurde.

In diesem Code wird zweimal die End-Anweisung verwendet. Das ist soweit nicht schlimm. Stellen Sie sich nun vor, Sie wollen den Wert der Variablen a ausgeben, sobald man versucht, das Programm zu schließen. Sie müssten nun alle Vorkommnisse der End-Anweisung um einen solchen Befehl erweitern.

Crystal Clear app terminal.png Code:  

Module Beispiel
    Sub Main()
        Console.Write("Geben Sie eine Zahl ein: ")
        Dim a As Integer = Console.ReadLine()
        Do
            a = 2 * a
            If a = 4 Then
                Console.WriteLine(a)
                 Console.ReadLine()
                End
            End If
        Loop Until a > 100
        Console.WriteLine(a)
        Console.ReadLine()
        End
    End Sub
  End Module

Crystal Clear app kscreensaver.png Ausgabe:  

4 (für a = 1)
4 (für a = 2)
192 (für a = 3)
128 (für a = 4)

Auf den ersten Blick lassen sich der Code und insbesondere die Console.Writeline-Aufrufe nicht mehr so leicht überblicken, die ganze Sache wird unübersichtlich. Diese Unübersichtlichkeit verstärkt sich noch, wenn Sie mehrere solche Befehle hinzufügen, sodass das Beenden letzlich viele Zeilen umfasst. Nun werfen Sie einen Blick auf den folgenden Code, der genau das gleiche bewirkt:

Crystal Clear app terminal.png Code:  

Module Beispiel
    Dim a As Integer
    Sub Main()
        Console.Write("Geben Sie eine Zahl ein: ")
        a = Console.ReadLine()
        Do
            a = 2 * a
            If a = 4 Then
                beendeDasProgramm()
            End If
        Loop Until a > 100
        beendeDasProgramm()
    End Sub
    Sub beendeDasProgramm()
        Console.WriteLine(a)
        Console.ReadLine()
        End
    End Sub
 End Module

Crystal Clear app kscreensaver.png Ausgabe:  

4 (für a = 1)
4 (für a = 2)
192 (für a = 3)
128 (für a = 4)

Nun wurde eine Funktion namens „BeendeDasProgramm“ definiert, ein wörtlich zu nehmender Befehl an den Computer, das Programm zu beenden. Zwischen Sub BeendeDasProgramm() und End Sub finden sich die Anweisungen, die das Programm korrekt beenden. Diese Anweisungen sind aus der Main()-Funktion verschwunden, stattdessen sehen wir BeendeDasProgramm(). Dieser Befehl ruft die Funktion auf, d.h. es werden die Befehle und Anweisungen in der Funktion ausgeführt, dann setzt das Programm am Ursprungsort des Aufrufs fort.

Vielleicht ist Ihnen schon aufgefallen, dass die Deklaration der Variable hier nicht innerhalb der Funktion Main() passiert, sondern schon davor. Das hängt damit zusammen, dass die Variable a, wenn Sie in der Funktion Main() deklariert wird, auch nur da verfügbar ist. Sie werden dann innerhalb einer anderen Funktion, hier BeendeDasProgramm, nicht auf die Variable zugreifen können. In diesem Fall ist die Variable lokal, denn sie ist auf eine bestimmte Lokalität, hier die Funktion Main() beschränkt. Wenn eine Variable in mehreren Funktionen verfügbar sein soll, muss sie global deklariert werden. Das bedeutet, dass die Variable nicht an eine bestimmte Funktion gebunden ist, sondern in allen Funktionen verfügbar ist. Um eine Variable global zu deklarieren, notieren Sie die Dim-Anweisung zwischen Module Beispiel und End Module, aber nicht innerhalb einer Funktion. Der Übersicht halber werden die Dim-Anweisungen für globale Variablen meist ganz oben in die Klassendefinition, also direkt nach Module ..., gestellt. Sie können die Deklarationen aber auch zwischen zwei Funktionen platzieren. Wir werden uns später noch einmal genauer und allgemeiner mit globalen und lokalen Variablen befassen.

Arbeit mit Funktionen[Bearbeiten]

Das Beispiel zeigt, wie Funktionen definiert werden: Die erste Zeile der Funktion beginnt mit Sub, gefolgt vom Funktionsnamen und einem leeren Klammerpaar. (Wir werden dieses Paar bald mit Leben füllen.) Für Funktionsnamen gelten die gleichen Regeln wie für Variablennamen: Erlaubt sind nur Buchstaben, Ziffern und Unterstriche, das erste Zeichen muss ein Buchstabe sein. Diese einleitende Zeile heißt Funktionskopf. Sie charakterisiert die Schnittstelle, über die die Funktion verwendet wird. Da dieses Verhalten ähnlich zur Variablendeklaration ist, die die Variable charakterisiert (über den Datentyp und evtl. die Feldgrenzen), heißt der Funktionskopf auch Funktionsdeklaration.

Nach dieser einleitenden Zeile folgt der sogenannte Funktionsrumpf. Er enthält alle Anweisungen und Befehle, die von der Funktion ausgeführt werden, sobald sie aufgerufen wird. Abschließend begrenzt die Anweisung End Sub die Funktion nach unten hin. Da dieser Bereich das Verhalten der Funktion definiert, heißt der Funktionsrumpf auch Funktionsdefinition.

Der Inhalt von Main Alle Funktionsaufrufe sind Befehle. Auch der Befehl System.Console.WriteLine ist ein Funktionsaufruf. Als aufmerksamer Leser sollte sich Ihnen jetzt auffallen, dass Funktionsnamen keine Punkte enthalten dürfen, dieser es aber offensichtlicherweise tut. Das ist richtig und falsch. Die Funktion, die wir hier aufrufen, heißt nicht System.Console.WriteLine, sondern nur WriteLine. Ich habe ja eben bewusst gesagt, dass der Funktionsaufruf einen Namen enthält, „mit dem die Funktion eindeutig identifiziert wird“. Dieser Name heißt auch Funktionsbezeichner.

Denken Sie zur Erklärung an eines der ersten Kapitel, in dem es um das „Hello World“-Programm ging. .NET stellt uns tausende von Objekten mit zahlreichen Funktionen (im wahrsten Sinne des Wortes) zur Verfügung. Die Objekte sind in Namensräumen geordnet, die wiederum in Namensräumen geordnet sein können. Ähnlich ist es mit Dateien (Objekten), die in Ordnern (Namensräumen) geordnet werden, die wiederum in Ordnern geordnet werden können.

Dieser Ordnung gerecht werdend gehört auch die Funktion BeendeDasProgramm zum Objekt Beispiel. Vielleicht denken Sie jetzt, dass der Aufruf über den Bezeichner Beispiel.BeendeDasProgramm erfolgen müsste. Wenn Sie allein zu dieser Überlegung gelangt sind, haben Sie schon eines der wesentlichen Konzepte der Objektorientierten Programmierung (OOP) verstanden, dass jedoch erst viel später genauer ausgeführt wird. Dort werden Sie auch sehen, dass Beispiel.BeendeDasProgramm falsch ist; es müsste Me.BeendeDasProgramm heißen. Doch dafür muss man sich genauer mit OOP beschäftigen, was an dieser Stelle noch nicht das Thema sein soll. Für jetzt nur soviel: Da Main() zum selben Objekt wie BeendeDasProgramm gehört, nämlich zu Beispiel, reicht es, wenn man einfach nur den Funktionsnamen als Bezeichner verwendet, also die Funktion nur über den Bezeichner BeendeDasProgramm aufruft. Das wird bis zur Einführung in die OOP immer so sein, denn erst dann werden wir mehrere Objekte verwenden.