次の方法で共有


インターフェイス (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 メソッドには、formatという名前の型stringの 1 つのパラメーターがあります。

インターフェイスを実装するには、オブジェクト式を使用する方法と型を使用する方法の 2 つの方法があります。 どちらの場合も、型またはオブジェクト式は、インターフェイスの抽象メソッドのメソッド本体を提供します。 実装は、インターフェイスを実装する各型に固有です。 そのため、異なる型のインターフェイス メソッドが互いに異なる場合があります。

キーワードの interfaceendは、定義の先頭と末尾を示すものであり、軽量構文を使用する場合は省略可能です。 これらのキーワードを使用しない場合、コンパイラは、使用するコンストラクトを分析して、型がクラスかインターフェイスかを推測しようとします。 メンバーを定義するか、他のクラス構文を使用する場合、型はクラスとして解釈されます。

.NET コーディング スタイルは、すべてのインターフェイスを大文字の Iで開始することです。

F#スタイルと .NET スタイル。 両方とも .NET コンシューマーに対して同じ方法でコンパイルされますが、F# スタイルの呼び出し元は F# スタイルのパラメーター アプリケーションと .NET スタイルでは、F# 呼び出し元がタプル引数アプリケーションを使用するように強制されます。

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

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

クラス型を使用したインターフェイスの実装

次のコードに示すように、 interface キーワード、インターフェイスの名前、および with キーワードの後にインターフェイス メンバー定義を使用して、クラス型に 1 つ以上のインターフェイスを実装できます。

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

インターフェイスの継承

インターフェイスは、1 つ以上の基本インターフェイスから継承できます。

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"

こちらも参照ください