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"

Lihat juga