Methoden (F#)
Eine Methode ist eine Funktion, die einem Typ zugeordnet ist.In der objektorientierten Programmierung werden Methoden verwendet, um die Funktionalität und das Verhalten von Objekten und Typen verfügbar zu machen und zu implementieren.
// Instance method definition.
[ attributes ]
member [inline] self-identifier.method-name parameter-list [ : return-type ]=
method-body
// Static method definition.
[ attributes ]
static member [inline] method-name parameter-list [ : return-type ]=
method-body
// Abstract method declaration or virtual dispatch slot.
[ attributes ]
abstract member self-identifier.method-name : type-signature
// Virtual method declaration and default implementation.
[ attributes ]
abstract member [inline] self-identifier.method-name : type-signature
[ attributes ]
default member [inline] self-identifier.method-name parameter-list[ : return-type ] =
method-body
// Override of inherited virtual method.
[ attributes ]
override member [inline] self-identifier.method-name parameter-list [ : return-type ]=
method-body
Hinweise
Die obige Syntax veranschaulicht die verschiedenen Formen von Methodendeklarationen und -definitionen.In längerem Methodentext folgt auf das Gleichheitszeichen (=) ein Zeilenumbruch, und der gesamte Methodentext wird eingezogen.
Auf jede Methodendeklaration können Attribute angewendet werden.Sie sind der Syntax für eine Methodendefinition vorangestellt und werden normalerweise in einer eigenen Zeile aufgeführt.Weitere Informationen finden Sie unter Attribute (F#).
Methoden können als inline markiert werden.Informationen zu inline finden Sie unter Inlinefunktionen (F#).
Nicht-Inlinemethoden können rekursiv im Typ verwendet werden; es besteht keine Notwendigkeit, das rec-Schlüsselwort explizit zu verwenden.
Instanzmethoden
Instanzmethoden werden mit dem member-Schlüsselwort und einem self-identifier, gefolgt von einem Punkt (.), sowie dem Methodennamen und den Parametern deklariert.Wie bei let-Bindungen kann die parameter-list ein Muster sein.In der Regel werden Methodenparameter als Tupel in Klammern eingeschlossen. So werden Methoden in F# dargestellt, wenn sie in anderen .NET Framework-Sprachen erstellt werden.Die Curry-Form (durch Leerzeichen getrennte Parameter) ist jedoch ebenfalls üblich, und es werden auch weitere Muster unterstützt.
Im folgenden Beispiel werden Definition und Verwendung einer nicht abstrakten Instanzmethode veranschaulicht.
type SomeType(factor0: int) =
let factor = factor0
member this.SomeMethod(a, b, c) =
(a + b + c) * factor
member this.SomeOtherMethod(a, b, c) =
this.SomeMethod(a, b, c) * factor
Verwenden Sie in Instanzmethoden nicht den Selbstbezeichner für den Zugriff auf Felder, die mithilfe von let-Bindungen definiert werden.Verwenden Sie den Selbstbezeichner, wenn Sie auf andere Member und Eigenschaften zugreifen.
Statische Methoden
Mit dem Schlüsselwort static wird angegeben, dass eine Methode ohne Instanz aufgerufen werden kann und keiner Objektinstanz zugeordnet ist.Andernfalls sind Methoden Instanzmethoden.
Das Beispiel im nächsten Abschnitt veranschaulicht mit dem let-Schlüsselwort deklarierte Felder, mit dem member-Schlüsselwort deklarierte Eigenschaftenmember und eine mit dem static-Schlüsselwort deklarierte statische Methode.
Im folgenden Beispiel werden Definition und Verwendung von statischen Methoden veranschaulicht.Angenommen, diese Methodendefinitionen befinden sich in der SomeType-Klasse des vorherigen Abschnitts.
static member SomeStaticMethod(a, b, c) =
(a + b + c)
static member SomeOtherStaticMethod(a, b, c) =
SomeType.SomeStaticMethod(a, b, c) * 100
Abstrakte und virtuelle Methoden
Das Schlüsselwort abstract gibt an, dass eine Methode über einen virtuellen Dispatchslot verfügt und möglicherweise nicht in der Klasse definiert ist.Ein virtueller Dispatchslot ist ein Eintrag in einer intern verwalteten Tabelle von Funktionen, anhand derer zur Laufzeit virtuelle Funktionsaufrufe in einem objektorientierten Typ gesucht werden.Der virtuelle Dispatchmechanismus ist der Mechanismus, der Polymorphie, eine wichtige Funktion der objektorientierten Programmierung, implementiert.Eine Klasse, die über mindestens eine abstrakte Methode ohne Definition verfügt, ist eine abstrakte Klasse. Dies bedeutet, dass keine Instanzen dieser Klasse erstellt werden können.Weitere Informationen zu abstrakten Klassen finden Sie unter Abstrakte Klassen (F#).
Abstrakte Methodendeklarationen enthalten keinen Methodentext.Stattdessen folgt auf den Namen der Methode ein Doppelpunkt (:) und eine Typsignatur für die Methode.Die Typsignatur einer Methode ist mit dem Text (jedoch ohne Parameternamen) identisch, der von IntelliSense angezeigt wird, wenn im Visual Studio-Code-Editor mit dem Mauszeiger auf einen Methodennamen gezeigt wird.Typsignaturen werden auch vom Interpreter "fsi.exe" angezeigt, wenn Sie interaktiv arbeiten.Die Typsignatur einer Methode wird gebildet, indem die Typen der Parameter, gefolgt vom Rückgabetyp, mit den entsprechenden Trennzeichen aufgeführt werden.Curry-Parameter werden durch -> und Tupelparameter durch * getrennt.Der Rückgabewert wird immer durch das Symbol - > von den Argumenten getrennt.Mithilfe von Klammern können komplexe Parameter, z. B. ein Funktionstyp als Parameter, in Gruppen zusammengefasst werden, oder mit Klammern kann angegeben werden, dass ein Tupel als einzelner Parameter und nicht als zwei Parameter behandelt wird.
Sie können auch abstrakten Methoden Standarddefinitionen zuweisen, indem Sie der Klasse die Definition hinzufügen und das default-Schlüsselwort verwenden, wie im Syntaxblock in diesem Thema gezeigt.Eine abstrakte Methode mit einer Definition in der gleichen Klasse entspricht einer virtuellen Methode in anderen .NET Framework-Sprachen.Unabhängig davon, ob eine Definition vorhanden ist, wird mit dem abstract-Schlüsselwort ein neuer Dispatchslot in der Tabelle virtueller Funktionen für die Klasse erstellt.
Unabhängig davon, ob eine Basisklasse ihre abstrakten Methoden implementiert, können abgeleitete Klassen Implementierungen abstrakter Methoden bereitstellen.Definieren Sie zum Implementieren einer abstrakten Methode in einer abgeleiteten Klasse eine Methode, die in der abgeleiteten Klasse über den gleichen Namen und die gleiche Signatur verfügt. Verwenden Sie jedoch das override-Schlüsselwort oder das default-Schlüsselwort, und stellen Sie den Methodentext bereit.Die Schlüsselwörter override und default haben die gleiche Bedeutung.Verwenden Sie override, wenn die neue Methode eine Basisklassenimplementierung überschreibt, und verwenden Sie default, wenn Sie eine Implementierung in der gleichen Klasse wie in der ursprünglich als abstrakt deklarierten Klasse erstellen.Verwenden Sie das abstract-Schlüsselwort nicht für die Methode, die die in der Basisklasse als abstrakt deklarierte Methode implementiert.
Das folgende Beispiel veranschaulicht die abstrakte Rotate-Methode, die über eine Standardimplementierung verfügt und einer virtuellen .NET Framework-Methode entspricht.
type Ellipse(a0 : float, b0 : float, theta0 : float) =
let mutable axis1 = a0
let mutable axis2 = b0
let mutable rotAngle = theta0
abstract member Rotate: float -> unit
default this.Rotate(delta : float) = rotAngle <- rotAngle + delta
Im folgenden Beispiel wird eine abgeleitete Klasse veranschaulicht, die eine Basisklassenmethode überschreibt.In diesem Fall ändert die Überschreibung das Verhalten, sodass die Methode keine Aktion ausführt.
type Circle(radius : float) =
inherit Ellipse(radius, radius, 0.0)
// Circles are invariant to rotation, so do nothing.
override this.Rotate(_) = ()
Überladene Methoden
Überladene Methoden sind Methoden, die über identische Namen in einem angegebenen Typ, jedoch über unterschiedliche Argumente verfügen.In F# werden normalerweise statt überladener Methoden optionale Argumente verwendet.Überladene Methoden sind jedoch in F# zulässig, sofern die Argumente in Tupelform und nicht in Curry-Form angegeben werden.
Beispiel: Eigenschaften und Methoden
Das folgende Beispiel enthält einen Typ, der Beispiele für Felder, private Funktionen, Eigenschaften und eine statische Methode bietet.
type RectangleXY(x1 : float, y1: float, x2: float, y2: float) =
// Field definitions.
let height = y2 - y1
let width = x2 - x1
let area = height * width
// Private functions.
static let maxFloat (x: float) (y: float) =
if x >= y then x else y
static let minFloat (x: float) (y: float) =
if x <= y then x else y
// Properties.
// Here, "this" is used as the self identifier,
// but it can be any identifier.
member this.X1 = x1
member this.Y1 = y1
member this.X2 = x2
member this.Y2 = y2
// A static method.
static member intersection(rect1 : RectangleXY, rect2 : RectangleXY) =
let x1 = maxFloat rect1.X1 rect2.X1
let y1 = maxFloat rect1.Y1 rect2.Y1
let x2 = minFloat rect1.X2 rect2.X2
let y2 = minFloat rect1.Y2 rect2.Y2
let result : RectangleXY option =
if ( x2 > x1 && y2 > y1) then
Some (RectangleXY(x1, y1, x2, y2))
else
None
result
// Test code.
let testIntersection =
let r1 = RectangleXY(10.0, 10.0, 20.0, 20.0)
let r2 = RectangleXY(15.0, 15.0, 25.0, 25.0)
let r3 : RectangleXY option = RectangleXY.intersection(r1, r2)
match r3 with
| Some(r3) -> printfn "Intersection rectangle: %f %f %f %f" r3.X1 r3.Y1 r3.X2 r3.Y2
| None -> printfn "No intersection found."
testIntersection