インターフェイスは 、他のクラスが実装する関連メンバーのセットを指定します。
構文
// 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 つの方法があります。 どちらの場合も、型またはオブジェクト式は、インターフェイスの抽象メソッドのメソッド本体を提供します。 実装は、インターフェイスを実装する各型に固有です。 そのため、異なる型のインターフェイス メソッドが互いに異なる場合があります。
キーワードの interface
と end
は、定義の先頭と末尾を示すものであり、軽量構文を使用する場合は省略可能です。 これらのキーワードを使用しない場合、コンパイラは、使用するコンストラクトを分析して、型がクラスかインターフェイスかを推測しようとします。 メンバーを定義するか、他のクラス構文を使用する場合、型はクラスとして解釈されます。
.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"
こちらも参照ください
.NET