Metoder
En metod är en funktion som är associerad med en typ. I objektorienterad programmering används metoder för att exponera och implementera funktioner och beteende för objekt och typer.
Syntax
// 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 ]
Kommentarer
I den tidigare syntaxen kan du se de olika formerna av metoddeklarationer och definitioner. I längre metodkroppar följer en radbrytning likhetstecknet (=) och hela metodtexten är indragen.
Attribut kan tillämpas på valfri metoddeklaration. De föregår syntaxen för en metoddefinition och visas vanligtvis på en separat rad. Mer information finns i Attribut.
Metoder kan markeras inline
. Mer information om inline
finns i Infogade funktioner.
Icke-infogade metoder kan användas rekursivt inom typen; det finns inget behov av att uttryckligen använda nyckelordet rec
.
Instansmetoder
Instansmetoder deklareras med nyckelordet member
och en självidentifierare, följt av en punkt (.) och metodnamnet och parametrarna. Precis som för let
bindningar kan parameterlistan vara ett mönster. Vanligtvis omger du metodparametrar i parenteser i tupplar, vilket är hur metoderna visas i F# när de skapas på andra .NET Framework-språk. Men den curryform (parametrar avgränsade med blanksteg) är också vanligt, och andra mönster stöds också.
I följande exempel visas definitionen och användningen av en icke-abstrakt instansmetod.
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
Använd inte självidentifieraren för att komma åt fält som definierats med hjälp av let-bindningar i instansmetoder. Använd självidentifieraren vid åtkomst till andra medlemmar och egenskaper.
Statiska metoder
static
Nyckelordet används för att ange att en metod kan anropas utan en instans och inte är associerad med en objektinstans. Annars är metoder instansmetoder.
I exemplet i nästa avsnitt visas fält som deklarerats med nyckelordet let
, egenskapsmedlemmar som deklarerats med nyckelordet member
och en statisk metod som deklarerats med nyckelordet static
.
I följande exempel visas definitionen och användningen av statiska metoder. Anta att dessa metoddefinitioner finns i SomeType
klassen i föregående avsnitt.
static member SomeStaticMethod(a, b, c) =
(a + b + c)
static member SomeOtherStaticMethod(a, b, c) =
SomeType.SomeStaticMethod(a, b, c) * 100
Abstrakta och virtuella metoder
Nyckelordet abstract
anger att en metod har ett virtuellt sändningsfack och kanske inte har någon definition i klassen. Ett virtuellt sändningsfack är en post i en internt underhållen tabell med funktioner som används vid körning för att söka efter virtuella funktionsanrop i en objektorienterad typ. Den virtuella sändningsmekanismen är den mekanism som implementerar polymorfism, en viktig funktion i objektorienterad programmering. En klass som har minst en abstrakt metod utan definition är en abstrakt klass, vilket innebär att inga instanser kan skapas av den klassen. Mer information om abstrakta klasser finns i Abstrakta klasser.
Abstrakta metoddeklarationer innehåller inte någon metodtext. I stället följs namnet på metoden av ett kolon (:) och en typsignatur för metoden. Typsignaturen för en metod är samma som den som visas av IntelliSense när du pausar muspekaren över ett metodnamn i Visual Studio Code-redigeraren, förutom utan parameternamn. Typsignaturer visas också av tolken, fsi.exe, när du arbetar interaktivt. Typsignaturen för en metod skapas genom att lista ut typerna av parametrarna, följt av returtypen, med lämpliga avgränsarsymboler. Curryparametrar avgränsas med ->
och tuppelns parametrar avgränsas med *
. Returvärdet avgränsas alltid från argumenten med en ->
symbol. Parenteser kan användas för att gruppera komplexa parametrar, till exempel när en funktionstyp är en parameter, eller för att ange när en tuppel behandlas som en enskild parameter i stället för som två parametrar.
Du kan också ge abstrakta metoder standarddefinitioner genom att lägga till definitionen i klassen och använda nyckelordet default
, som du ser i syntaxblocket i det här avsnittet. En abstrakt metod som har en definition i samma klass motsvarar en virtuell metod på andra .NET Framework-språk. Oavsett om det finns en definition skapar nyckelordet abstract
ett nytt dispatch-fack i den virtuella funktionstabellen för klassen.
Oavsett om en basklass implementerar sina abstrakta metoder kan härledda klasser tillhandahålla implementeringar av abstrakta metoder. Om du vill implementera en abstrakt metod i en härledd klass definierar du en metod som har samma namn och signatur i den härledda klassen, förutom att använda nyckelordet override
eller default
och ange metodtexten. Nyckelorden override
och default
betyder exakt samma sak. Använd override
om den nya metoden åsidosätter en basklassimplementering. Använd default
när du skapar en implementering i samma klass som den ursprungliga abstrakta deklarationen. Använd inte nyckelordet abstract
för metoden som implementerar metoden som förklarades abstrakt i basklassen.
I följande exempel visas en abstrakt metod Rotate
som har en standardimplementering, motsvarande en virtuell .NET Framework-metod.
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
I följande exempel visas en härledd klass som åsidosätter en basklassmetod. I det här fallet ändrar åsidosättningen beteendet så att metoden inte gör någonting.
type Circle(radius: float) =
inherit Ellipse(radius, radius, 0.0)
// Circles are invariant to rotation, so do nothing.
override this.Rotate(_) = ()
Överlagrade metoder
Överlagrade metoder är metoder som har identiska namn i en viss typ men som har olika argument. I F# används vanligtvis valfria argument i stället för överlagrade metoder. Överlagrade metoder är dock tillåtna på språket, förutsatt att argumenten är i tuppelns form, inte i curryform.
Valfria argument
Från och med F# 4.1 kan du också ha valfria argument med ett standardparametervärde i metoder. Detta är för att underlätta samverkan med C#-kod. I följande exempel visas syntaxen:
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
Observera att det värde som skickas in för DefaultParameterValue
måste matcha indatatypen. I exemplet ovan är det en int
. Ett försök att skicka ett icke-heltalsvärde till DefaultParameterValue
skulle resultera i ett kompileringsfel.
Exempel: Egenskaper och metoder
Följande exempel innehåller en typ som innehåller exempel på fält, privata funktioner, egenskaper och en statisk metod.
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