Antarmuka (F#)
Antarmuka menentukan set anggota terkait yang diterapkan kelas lain.
Sintaks
// 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
Keterangan
Deklarasi antarmuka menyerupai deklarasi kelas kecuali bahwa tidak ada anggota yang diimplementasikan. Sebaliknya, semua anggota abstrak, seperti yang ditunjukkan oleh kata kunci abstract
. Anda tidak menyediakan isi metode untuk metode abstrak. F# tidak dapat menentukan implementasi metode default pada antarmuka, tetapi kompatibel dengan implementasi default yang ditentukan oleh C#. Implementasi default menggunakan default
kata kunci hanya didukung saat mewarisi dari kelas dasar non-antarmuka.
Aksesibilitas default untuk antarmuka adalah public
.
Anda dapat secara opsional memberi nama pada setiap parameter metode menggunakan sintaks F# normal:
type ISprintable =
abstract member Print: format: string -> unit
Dalam contoh di atas ISprintable
, metode Print
memiliki parameter tunggal dari jenis string
dengan nama format
.
Ada dua cara untuk menerapkan antarmuka: dengan menggunakan ekspresi objek, dan dengan menggunakan jenis. Dalam kedua kasus, jenis atau ekspresi objek menyediakan badan metode untuk metode abstrak antarmuka. Implementasi khusus untuk setiap jenis yang mengimplementasikan antarmuka. Oleh karena itu, metode antarmuka pada berbagai jenis mungkin berbeda satu sama lain.
Kata kunci interface
dan end
, yang menandai awal dan akhir definisi, bersifat opsional saat Anda menggunakan sintaks ringan. Jika Anda tidak menggunakan kata kunci ini, pengkompilasi mencoba menyimpulkan apakah jenisnya adalah kelas atau antarmuka dengan menganalisis konstruksi yang Anda gunakan. Jika Anda menentukan anggota atau menggunakan sintaks kelas lainnya, jenisnya ditafsirkan sebagai kelas.
Gaya pengkodean .NET adalah memulai semua antarmuka dengan modal I
.
Anda dapat menentukan beberapa parameter dengan dua cara: F#-style dan .NET-style. Keduanya akan mengkompilasi cara yang sama untuk konsumen .NET, tetapi F#-style akan memaksa pemanggil F# untuk menggunakan aplikasi parameter F#-style dan .NET-style akan memaksa pemanggil F# untuk menggunakan aplikasi argumen yang disematkan.
type INumericFSharp =
abstract Add: x: int -> y: int -> int
type INumericDotNet =
abstract Add: x: int * y: int -> int
Menerapkan Antarmuka dengan Menggunakan Jenis Kelas
Anda dapat mengimplementasikan satu atau beberapa antarmuka dalam jenis kelas dengan menggunakan interface
kata kunci, nama antarmuka, dan with
kata kunci, diikuti oleh definisi anggota antarmuka, seperti yang ditunjukkan dalam kode berikut.
type IPrintable =
abstract member Print: unit -> unit
type SomeClass1(x: int, y: float) =
interface IPrintable with
member this.Print() = printfn "%d %f" x y
Implementasi antarmuka diwariskan, sehingga kelas turunan apa pun tidak perlu melengkapinya kembali.
Metode Antarmuka Panggilan
Metode antarmuka hanya dapat dipanggil melalui antarmuka, bukan melalui objek jenis apa pun yang mengimplementasikan antarmuka. Dengan demikian, Anda mungkin harus meningkatkan ke jenis antarmuka dengan menggunakan :>
operator atau upcast
operator untuk memanggil metode ini.
Untuk memanggil metode antarmuka saat Anda memiliki objek jenis SomeClass
, Anda harus meningkatkan objek ke jenis antarmuka, seperti yang ditunjukkan dalam kode berikut.
let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()
Alternatifnya adalah mendeklarasikan metode pada objek yang meningkatkan dan memanggil metode antarmuka, seperti dalam contoh berikut.
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()
Menerapkan Antarmuka dengan Menggunakan Ekspresi Objek
Ekspresi objek menyediakan cara singkat untuk mengimplementasikan antarmuka. Ini berguna ketika Anda tidak perlu membuat jenis bernama, dan Anda hanya ingin objek yang mendukung metode antarmuka, tanpa metode tambahan. Ekspresi objek diilustrasikan dalam kode berikut.
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()
Pewarisan Antarmuka
Antarmuka dapat mewarisi dari satu atau lebih antarmuka lainnya.
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
Menerapkan antarmuka dengan implementasi default
C# mendukung penentuan antarmuka dengan implementasi default, seperti:
using System;
namespace CSharp
{
public interface MyDim
{
public int Z => 0;
}
}
Ini langsung dapat dikonsumsi dari 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}"
Anda dapat mengambil alih implementasi default dengan override
, seperti mengambil alih anggota virtual apa pun.
Setiap anggota dalam antarmuka yang tidak memiliki implementasi default masih harus diimplementasikan secara eksplisit.
Menerapkan antarmuka yang sama pada instansiasi generik yang berbeda
F# mendukung penerapan antarmuka yang sama pada instansiasi generik yang berbeda seperti:
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"