Dela via


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 inlinefinns 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

Se även