Megosztás a következőn keresztül:


Interfészek (F#)

Az interfészek olyan kapcsolódó tagcsoportokat határoznak meg, amelyeket más osztályok implementálnak.

Syntax

// Interface declaration:
[ attributes ]
type [accessibility-modifier] interface-name =
    [ interface ]     [ inherit base-interface-name ...]
    abstract member1 : [ argument-types1 -> ] return-type1
    abstract member2 : [ argument-types2 -> ] return-type2
    ...
[ end ]

// Implementing, inside a class type definition:
interface interface-name with
    member self-identifier.member1argument-list = method-body1
    member self-identifier.member2argument-list = method-body2

// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
    { new interface-name with
        member self-identifier.member1argument-list = method-body1
        member self-identifier.member2argument-list = method-body2
        [ base-interface-definitions ]
    }
    member-list

Megjegyzések

A felületi deklarációk az osztálydeklarációkhoz hasonlítanak, azzal a kivételével, hogy nincsenek tagok implementálva. Ehelyett az összes tag absztrakt, ahogy azt a kulcsszó abstractis jelzi. Az absztrakt metódusokhoz nem ad meg metódustörzset. Az F# nem tud alapértelmezett metódus-implementációt definiálni egy felületen, de kompatibilis a C# által definiált alapértelmezett implementációkkal. A kulcsszót használó default alapértelmezett implementációk csak akkor támogatottak, ha nem felületi alaposztályból örökölnek.

A felületek alapértelmezett akadálymentessége a következő public: .

Az egyes metódusparaméterek megadhatnak egy nevet normál F# szintaxissal:

type ISprintable =
    abstract member Print: format: string -> unit

A fenti példában a Print metódusnak egyetlen paramétere van a típusnak string a nevévelformat.ISprintable

Az interfészek kétféleképpen implementálhatók: objektumkifejezések használatával és típusok használatával. A típus- vagy objektumkifejezés mindkét esetben metódustesteket biztosít a felület absztrakt metódusaihoz. Az implementációk minden olyan típusra vonatkoznak, amely implementálja az interfészt. Ezért a különböző típusok felületi metódusai eltérhetnek egymástól.

A definíció kezdetét és végét jelző kulcsszavak interfaceendnem kötelezőek, ha egyszerűsített szintaxist használ. Ha nem használja ezeket a kulcsszavakat, a fordító a használt szerkezetek elemzésével megpróbálja megállapítani, hogy a típus osztály vagy felület-e. Ha tagot határoz meg, vagy más osztályszintaxist használ, a rendszer osztályként értelmezi a típust.

A .NET kódolási stílusa az, hogy az összes felületet nagybetűvel Ikezdje.

Kétféleképpen adhat meg több paramétert: F#-style és . NET-stílus. Mindkettő ugyanúgy fog összeállni a .NET-felhasználók számára, de az F#-stílus kényszeríti az F#-hívókat az F#-stílusú paraméteralkalmazás és a . A NET-stílus kényszeríti az F#-hívókat a csatolt argumentumalkalmazás használatára.

type INumericFSharp =
    abstract Add: x: int -> y: int -> int

type INumericDotNet =
    abstract Add: x: int * y: int -> int

Interfészek implementálása osztálytípusok használatával

Egy vagy több illesztőt egy osztálytípusban a kulcsszóval, az interface interfész nevével és a with kulcsszóval, majd a felülettagdefiníciókkal valósíthat meg, ahogyan az az alábbi kódban is látható.

type IPrintable =
    abstract member Print: unit -> unit

type SomeClass1(x: int, y: float) =
    interface IPrintable with
        member this.Print() = printfn "%d %f" x y

A felületi implementációk öröklődnek, így a származtatott osztályoknak nem kell újrakonfigurálnia őket.

Hívófelület metódusai

Az interfészmetódusok csak az interfészen keresztül hívhatók meg, az interfészt megvalósító objektumon keresztül nem. Így előfordulhat, hogy a metódusok meghívásához az operátort vagy az :>upcast operátort kell a felülettípusra felcímkenni.

A felület metódusának meghívásához, ha rendelkezik egy típusú SomeClassobjektummal, az objektumot a felület típusára kell felcímkenni, ahogyan az az alábbi kódban is látható.

let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()

Másik lehetőségként deklarálhat egy metódust azon az objektumon, amely az illesztőmetódusra hivatkozik és meghívja, ahogyan az alábbi példában is látható.

type SomeClass2(x: int, y: float) =
    member this.Print() = (this :> IPrintable).Print()

    interface IPrintable with
        member this.Print() = printfn "%d %f" x y

let x2 = new SomeClass2(1, 2.0)
x2.Print()

Felületek implementálása objektumkifejezések használatával

Az objektumkifejezések rövid módot biztosítanak egy felület implementálására. Ezek akkor hasznosak, ha nem kell névvel ellátott típust létrehoznia, és csak olyan objektumot szeretne, amely támogatja az interfészmetódusokat további metódusok nélkül. Az objektumkifejezéseket az alábbi kód szemlélteti.

let makePrintable (x: int, y: float) =
    { new IPrintable with
        member this.Print() = printfn "%d %f" x y }

let x3 = makePrintable (1, 2.0)
x3.Print()

Interfész öröklése

Az illesztők egy vagy több alapillesztőtől örökölhetnek.

type Interface1 =
    abstract member Method1: int -> int

type Interface2 =
    abstract member Method2: int -> int

type Interface3 =
    inherit Interface1
    inherit Interface2
    abstract member Method3: int -> int

type MyClass() =
    interface Interface3 with
        member this.Method1(n) = 2 * n
        member this.Method2(n) = n + 100
        member this.Method3(n) = n / 10

Interfészek implementálása alapértelmezett implementációkkal

A C# támogatja az alapértelmezett implementációkkal rendelkező felületek meghatározását, például:

using System;

namespace CSharp
{
    public interface MyDim
    {
        public int Z => 0;
    }
}

Ezek közvetlenül az F#-ból fogyaszthatók:

open CSharp

// You can implement the interface via a class
type MyType() =
    member _.M() = ()

    interface MyDim

let md = MyType() :> MyDim
printfn $"DIM from C#: %d{md.Z}"

// You can also implement it via an object expression
let md' = { new MyDim }
printfn $"DIM from C# but via Object Expression: %d{md'.Z}"

Az alapértelmezett implementációk felülbírálhatók például bármely virtuális tag felülbírálásával override.

A felület azon tagjait, amelyek nem rendelkeznek alapértelmezett implementációval, explicit módon kell implementálnunk.

Ugyanazon felület implementálása különböző általános példányokon

Az F# támogatja ugyanazt a felületet különböző általános példányokon, például:

type IA<'T> =
    abstract member Get : unit -> 'T

type MyClass() =
    interface IA<int> with
        member x.Get() = 1
    interface IA<string> with
        member x.Get() = "hello"

let mc = MyClass()
let iaInt = mc :> IA<int>
let iaString = mc :> IA<string>

iaInt.Get() // 1
iaString.Get() // "hello"

Lásd még