介面 (F#)
「介面」(Interface) 可指定其他類別實作的相關成員集合。
// Interface declaration:
[ attributes ]
type 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.member1 argument-list = method-body1
member self-identifier.member2 argument-list = method-body2
// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
{ new interface-name with
member self-identifier.member1 argument-list = method-body1
member self-identifier.member2 argument-list = method-body2
[ base-interface-definitions ]
}
member-list
備註
介面宣告類似類別宣告,不同的是未實作成員, 所有成員都是抽象,如同 abstract 關鍵字所表示。 您不必提供抽象方法的方法主體, 但是可以將做為方法的另一個成員定義與 default 關鍵字包含在一起,提供預設實作。 這樣做相當於以其他 .NET 語言建立基底類別的虛擬方法。 在實作介面的類別中可以覆寫這類虛擬方法。
使用物件運算式以及使用類別型別都可以實作介面。 無論哪種方式,類別型別或物件運算式都會提供介面之抽象方法的方法主體。 實作是每個實作介面之型別專屬的實作。 因此,不同型別的介面方法可能互異。
當您使用輕量型語法時,標示定義開頭和結尾的關鍵字 interface 和 end 是選擇性項目。 如果未使用這些關鍵字,編譯器會分析使用的建構,嘗試推斷型別是類別還是介面。 如果您定義成員或使用其他類別語法,型別就會解譯為類別。
.NET 程式碼撰寫風格是以大寫字 I 做為所有介面的開頭。
使用類別型別來實作介面
您可以使用 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
會繼承介面實作,因此任何衍生類別都不需要重新實作它們。
呼叫介面方法
介面方法只能透過介面來呼叫,不能透過實作介面之任何型別的物件來呼叫。 因此,您必須使用 :> 運算子或 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