共用方式為


介面 (F#)

介面 會指定其他類別實作的相關成員集合。

語法

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

備註

介面宣告與類別宣告類似,但未實作任何成員。 相反地,所有成員都是抽象的,如 關鍵詞 abstract所指示。 您不提供抽象方法的方法主體。 F# 無法在介面上定義預設方法實作,但與 C# 所定義的預設實作相容。 只有在繼承自非介面基類時,才支援使用 default 關鍵詞的默認實作。

介面的預設輔助功能為 public

您可以選擇性地使用一般 F# 語法為每個方法參數指定名稱:

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

在上述ISprintable範例中Print,方法具有名稱 為的型stringformat別單一參數。

有兩種方式可以實作介面:使用對象表達式,以及使用型別。 不論是哪一種情況,類型或物件表達式都提供介面抽象方法的方法主體。 實作是實作 介面的每個類型特有的。 因此,不同類型上的介面方法可能彼此不同。

當您使用輕量型語法時,標記定義開頭和結尾的關鍵詞 interfaceend是選擇性的。 如果您不使用這些關鍵詞,編譯程式會嘗試藉由分析您使用的建構來推斷類型是類別或介面。 如果您定義成員或使用其他類別語法,則類型會解譯為類別。

.NET 程式代碼撰寫樣式是以大寫 I開頭的所有介面。

您可以透過兩種方式指定多個參數:F#樣式和 。NET 樣式。 這兩者都會針對 .NET 取用者編譯相同的方式,但 F#-style 會強制 F# 呼叫者使用 F#-style 參數應用程式和 。NET 樣式會強制 F# 呼叫端使用 Tupled 自變數應用程式。

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

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

使用類別類型實作介面

您可以使用 關鍵詞、介面的名稱和 interface 關鍵詞,後面接著介面成員定義,在類別類型with中實作一或多個介面,如下列程式代碼所示。

type IPrintable =
    abstract member Print: unit -> unit

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

介面實作是繼承的,因此任何衍生類別都不需要重新實作它們。

定義空白或標記介面

空介面,也稱為標記介面,可用來識別一組類型,而不需要任何特定行為。 這些介面沒有成員,可作為標記或標記類型以進行分類的方式。

您可以使用以下 interface end 語法定義空白介面:

// Define an empty interface (also known as a marker interface)
type IMarker = 
    interface end

// Implement the empty interface in a record type
type MyRecord = 
    { Name: string }
    interface IMarker

// Implement the empty interface in a class type
type MyClass(value: int) =
    member _.Value = value
    interface IMarker

在上面的範例中, IMarker 定義為空介面。 兩者都 MyRecordMyClass 作此介面,而不需要提供任何方法實作,因為介面沒有成員。 這可讓您使用介面類型,以一般方式識別及使用這些類型。

呼叫介面方法

介面方法只能透過 介面呼叫,而不能透過實作介面之型別的任何物件呼叫。 因此,您可能必須使用 運算符或 :> 運算符來向上轉換至介面類型upcast,才能呼叫這些方法。

若要在類型為 SomeClass的物件時呼叫介面方法,您必須將 物件向上傳播至介面類型,如下列程式代碼所示。

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

替代方法是在物件上宣告方法,該方法會向上傳播並呼叫 介面方法,如下列範例所示。

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()

使用物件表達式實作介面

對象表達式提供實作介面的簡短方式。 當您不需要建立具名類型,而且您只需要支援介面方法的物件,而不需要任何其他方法時,它們就很有用。 下列程式代碼說明物件表達式。

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()

介面繼承

介面可以繼承自一或多個基底介面。

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

使用預設實作介面

C# 支援使用預設實作來定義介面,如下所示:

using System;

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

這些直接從 F# 取用:

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}"

您可以使用 覆寫預設實 override作,例如覆寫任何虛擬成員。

介面中沒有預設實作的任何成員仍必須明確實作。

在不同的泛型具現化上實作相同的介面

F# 支援在不同的泛型具現化上實作相同的介面,如下所示:

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"

另請參閱