Methoden
Een methode is een functie die is gekoppeld aan een type. In objectgeoriënteerde programmering worden methoden gebruikt om de functionaliteit en het gedrag van objecten en typen beschikbaar te maken en te implementeren.
Syntaxis
// 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 method-name : type-signature
// Virtual method declaration and default implementation.
[ attributes ]
abstract member method-name : type-signature
[ attributes ]
default self-identifier.method-name parameter-list [ : return-type ] =
method-body
// Override of inherited virtual method.
[ attributes ]
override self-identifier.method-name parameter-list [ : return-type ] =
method-body
// Optional and DefaultParameterValue attributes on input parameters
[ attributes ]
[ modifier ] member [inline] self-identifier.method-name ([<Optional; DefaultParameterValue( default-value )>] input) [ : return-type ]
Opmerkingen
In de vorige syntaxis ziet u de verschillende vormen van methodedeclaraties en definities. In langere methodeteksten volgt een regeleinde het gelijkteken (=) en wordt de hoofdtekst van de hele methode ingesprongen.
Kenmerken kunnen worden toegepast op elke methodedeclaratie. Ze gaan vooraf aan de syntaxis voor een methodedefinitie en worden meestal op een afzonderlijke regel weergegeven. Zie Kenmerken voor meer informatie.
Methoden kunnen worden gemarkeerd inline
. Zie Inline-functies voor meer informatie.inline
Niet-inlinemethoden kunnen recursief binnen het type worden gebruikt; u hoeft het rec
trefwoord niet expliciet te gebruiken.
Exemplaarmethoden
Exemplaarmethoden worden gedeclareerd met het member
trefwoord en een zelf-id, gevolgd door een punt (.) en de naam en parameters van de methode. Net als bij let
bindingen kan de parameterlijst een patroon zijn. Normaal gesproken plaatst u methodeparameters tussen haakjes in een tuple-formulier. Dit is de manier waarop methoden worden weergegeven in F# wanneer ze worden gemaakt in andere .NET Framework-talen. De curriede vorm (parameters gescheiden door spaties) is echter ook gebruikelijk en andere patronen worden ook ondersteund.
In het volgende voorbeeld ziet u de definitie en het gebruik van een niet-abstracte instantiemethode.
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
Gebruik binnen exemplaarmethoden de self-id niet voor toegang tot velden die zijn gedefinieerd met behulp van bindingen. Gebruik de self-id bij het openen van andere leden en eigenschappen.
Statische methoden
Het trefwoord static
wordt gebruikt om op te geven dat een methode zonder exemplaar kan worden aangeroepen en niet is gekoppeld aan een objectexemplaar. Anders zijn methoden exemplaarmethoden.
In het voorbeeld in de volgende sectie ziet u velden die zijn gedeclareerd met het let
trefwoord, eigenschapsleden die zijn gedeclareerd met het member
trefwoord en een statische methode die is gedeclareerd met het static
trefwoord.
In het volgende voorbeeld ziet u de definitie en het gebruik van statische methoden. Stel dat deze methodedefinities zich in de SomeType
klasse in de vorige sectie bevinden.
static member SomeStaticMethod(a, b, c) =
(a + b + c)
static member SomeOtherStaticMethod(a, b, c) =
SomeType.SomeStaticMethod(a, b, c) * 100
Abstracte en virtuele methoden
Het trefwoord abstract
geeft aan dat een methode een virtuele dispatchsite heeft en mogelijk geen definitie in de klasse heeft. Een virtuele dispatchsite is een vermelding in een intern onderhouden tabel met functies die tijdens runtime worden gebruikt om virtuele functieaanroepen in een objectgeoriënteerd type op te zoeken. Het virtuele verzendmechanisme is het mechanisme dat polymorfisme implementeert, een belangrijke functie van objectgeoriënteerde programmering. Een klasse met ten minste één abstracte methode zonder definitie is een abstracte klasse, wat betekent dat er geen exemplaren van die klasse kunnen worden gemaakt. Zie Abstract-klassen voor meer informatie over abstracte klassen.
Abstracte methodedeclaraties bevatten geen hoofdtekst van de methode. In plaats daarvan wordt de naam van de methode gevolgd door een dubbele punt (:) en een typehandtekening voor de methode. De typehandtekening van een methode is hetzelfde als die wordt weergegeven door IntelliSense wanneer u de muisaanwijzer boven een methodenaam in visual Studio Code Editor houdt, behalve zonder parameternamen. Typhandtekeningen worden ook weergegeven door de interpreter, fsi.exe, wanneer u interactief werkt. De typehandtekening van een methode wordt gevormd door de typen parameters weer te geven, gevolgd door het retourtype, met de juiste scheidingstekens. Curriede parameters worden gescheiden door ->
en tuple parameters worden gescheiden door *
. De retourwaarde wordt altijd gescheiden van de argumenten door een ->
symbool. Haakjes kunnen worden gebruikt om complexe parameters te groeperen, zoals wanneer een functietype een parameter is of om aan te geven wanneer een tuple wordt behandeld als één parameter in plaats van als twee parameters.
U kunt ook abstracte methoden standaarddefinities geven door de definitie toe te voegen aan de klasse en het default
trefwoord te gebruiken, zoals wordt weergegeven in het syntaxisblok in dit onderwerp. Een abstracte methode met een definitie in dezelfde klasse is gelijk aan een virtuele methode in andere .NET Framework-talen. Of er al dan niet een definitie bestaat, het abstract
trefwoord maakt een nieuwe dispatchsite in de virtuele functietabel voor de klasse.
Ongeacht of een basisklasse de abstracte methoden implementeert, kunnen afgeleide klassen implementaties van abstracte methoden bieden. Als u een abstracte methode in een afgeleide klasse wilt implementeren, definieert u een methode met dezelfde naam en handtekening in de afgeleide klasse, behalve het override
of default
het trefwoord, en geeft u de hoofdtekst van de methode op. De trefwoorden override
en default
betekenen precies hetzelfde. Gebruik deze methode als de nieuwe methode een basisklasse-implementatie overschrijft. Gebruik override
default
deze methode wanneer u een implementatie maakt in dezelfde klasse als de oorspronkelijke abstracte declaratie. Gebruik het abstract
trefwoord niet voor de methode waarmee de methode wordt geïmplementeerd die in de basisklasse is gedeclareerd.
In het volgende voorbeeld ziet u een abstracte methode Rotate
met een standaard implementatie, het equivalent van een virtuele .NET Framework-methode.
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
In het volgende voorbeeld ziet u een afgeleide klasse die een basisklassemethode overschrijft. In dit geval verandert de onderdrukking het gedrag zodat de methode niets doet.
type Circle(radius: float) =
inherit Ellipse(radius, radius, 0.0)
// Circles are invariant to rotation, so do nothing.
override this.Rotate(_) = ()
Overbelaste methoden
Overbelaste methoden zijn methoden die identieke namen hebben in een bepaald type, maar die verschillende argumenten hebben. In F# worden optionele argumenten meestal gebruikt in plaats van overbelaste methoden. Overbelaste methoden zijn echter toegestaan in de taal, mits de argumenten zich in tuplevorm bevinden, niet gecureerd.
Optionele argumenten
Vanaf F# 4.1 kunt u ook optionele argumenten hebben met een standaardparameterwaarde in methoden. Dit is bedoeld om samenwerking met C#-code te vergemakkelijken. In het volgende voorbeeld ziet u de syntaxis:
open System.Runtime.InteropServices
// A class with a method M, which takes in an optional integer argument.
type C() =
member _.M([<Optional; DefaultParameterValue(12)>] i) = i + 1
Houd er rekening mee dat de doorgegeven DefaultParameterValue
waarde moet overeenkomen met het invoertype. In het bovenstaande voorbeeld is het een int
. Als u probeert een niet-geheel getal door DefaultParameterValue
te geven, wordt er een compileerfout gegenereerd.
Voorbeeld: Eigenschappen en methoden
Het volgende voorbeeld bevat een type met voorbeelden van velden, privéfuncties, eigenschappen en een statische methode.
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