Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Schnittstellen geben Sätze verwandter Member an, die andere Klassen implementieren.
Syntax
// 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
Bemerkungen
Schnittstellendeklarationen ähneln Klassendeklarationen, mit der Ausnahme, dass keine Member implementiert werden. Stattdessen sind alle Elemente abstrakt, wie durch das Schlüsselwort abstractangegeben. Sie stellen keinen Methodentext für abstrakte Methoden bereit. F# kann keine Standardmethodenimplementierung auf einer Schnittstelle definieren, ist aber kompatibel mit Standardimplementierungen, die von C# definiert werden. Standardimplementierungen mit dem default Schlüsselwort werden nur unterstützt, wenn sie von einer Basisklasse ohne Schnittstelle erben.
Die Standardmäßige Barrierefreiheit für Schnittstellen lautet public.
Sie können optional jedem Methodenparameter einen Namen mit der normalen F#-Syntax zuweisen:
type ISprintable =
abstract member Print: format: string -> unit
Im obigen ISprintable Beispiel weist die Print Methode einen einzelnen Parameter des Typs string mit dem Namen formatauf.
Es gibt zwei Möglichkeiten zum Implementieren von Schnittstellen: mithilfe von Objektausdrücken und mithilfe von Typen. In beiden Fällen stellt der Typ oder der Objektausdruck Methodentexte für abstrakte Methoden der Schnittstelle bereit. Implementierungen sind spezifisch für jeden Typ, der die Schnittstelle implementiert. Daher können Schnittstellenmethoden für verschiedene Typen voneinander abweichen.
Die Schlüsselwörter interface und end, die den Anfang und das Ende der Definition markieren, sind optional, wenn Sie eine einfache Syntax verwenden. Wenn Sie diese Schlüsselwörter nicht verwenden, versucht der Compiler zu ermitteln, ob es sich bei dem Typ um eine Klasse oder eine Schnittstelle handelt, indem die verwendeten Konstrukte analysiert werden. Wenn Sie ein Element definieren oder eine andere Klassensyntax verwenden, wird der Typ als Klasse interpretiert.
Der .NET-Codierungsstil besteht darin, alle Schnittstellen mit einem Großbuchstaben Izu beginnen.
Sie können mehrere Parameter auf zwei Arten angeben: F#-style und . NET-Formatvorlage. Beide kompilieren die gleiche Methode für .NET-Consumer, aber F#-Style erzwingt F#-Aufrufer zur Verwendung der F#-Formatparameteranwendung und . Im NET-Stil wird erzwungen, dass F#-Aufrufer tuplierte Argumentanwendung verwenden.
type INumericFSharp =
abstract Add: x: int -> y: int -> int
type INumericDotNet =
abstract Add: x: int * y: int -> int
Implementieren von Schnittstellen mithilfe von Klassentypen
Sie können eine oder mehrere Schnittstellen in einem Klassentyp implementieren, indem Sie das interface Schlüsselwort, den Namen der Schnittstelle und das with Schlüsselwort verwenden, gefolgt von den Schnittstellenmememmdefinitionen, wie im folgenden Code gezeigt.
type IPrintable =
abstract member Print: unit -> unit
type SomeClass1(x: int, y: float) =
interface IPrintable with
member this.Print() = printfn "%d %f" x y
Schnittstellenimplementierungen werden geerbt, sodass alle abgeleiteten Klassen sie nicht erneut implementieren müssen.
Definieren leerer oder Markerschnittstellen
Leere Schnittstellen, auch als Markerschnittstellen bezeichnet, können verwendet werden, um einen Satz von Typen zu identifizieren, ohne dass ein bestimmtes Verhalten erforderlich ist. Diese Schnittstellen haben keine Member und dienen als Möglichkeit zum Markieren oder Kategorisieren von Typen für Kategorisierungszwecke.
Sie definieren eine leere Schnittstelle mithilfe der interface end Syntax:
// Define an empty interface (also known as a marker interface)
type IMarker =
interface end
// Implement the empty interface in a record type
type MyRecord =
{ Name: string }
interface IMarker
// Implement the empty interface in a class type
type MyClass(value: int) =
member _.Value = value
interface IMarker
Im obigen IMarker Beispiel wird als leere Schnittstelle definiert. Beide MyRecord und MyClass implementieren diese Schnittstelle, ohne Methodenimplementierungen bereitstellen zu müssen, da die Schnittstelle keine Member enthält. Auf diese Weise können Sie den Schnittstellentyp verwenden, um diese Typen auf gemeinsame Weise zu identifizieren und zu bearbeiten.
Aufrufen von Schnittstellenmethoden
Schnittstellenmethoden können nur über die Schnittstelle aufgerufen werden, nicht über ein Objekt des Typs, der die Schnittstelle implementiert. Daher müssen Sie möglicherweise den Schnittstellentyp mithilfe des :> Operators oder des upcast Operators aufsteigen, um diese Methoden aufzurufen.
Um die Schnittstellenmethode aufzurufen, wenn Sie über ein Objekt vom Typ verfügen SomeClass, müssen Sie das Objekt auf den Schnittstellentyp hochcasten, wie im folgenden Code gezeigt.
let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()
Eine Alternative besteht darin, eine Methode für das Objekt zu deklarieren, das die Schnittstellenmethode hochcasts und aufruft, wie im folgenden Beispiel gezeigt.
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()
Implementieren von Schnittstellen mithilfe von Objektausdrücken
Objektausdrücke bieten eine kurze Möglichkeit zum Implementieren einer Schnittstelle. Sie sind nützlich, wenn Sie keinen benannten Typ erstellen müssen, und Sie möchten nur ein Objekt, das die Schnittstellenmethoden unterstützt, ohne zusätzliche Methoden. Ein Objektausdruck wird im folgenden Code veranschaulicht.
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()
Schnittstellenvererbung
Schnittstellen können von einer oder mehreren Basisschnittstellen erben.
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
Implementieren von Schnittstellen mit Standardimplementierungen
C# unterstützt das Definieren von Schnittstellen mit Standardimplementierungen, z. B.:
using System;
namespace CSharp
{
public interface MyDim
{
public int Z => 0;
}
}
Diese sind direkt von F# konsumierbar:
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}"
Sie können eine Standardimplementierung mit overrideeinem beliebigen virtuellen Element außer Kraft setzen.
Alle Member in einer Schnittstelle, die nicht über eine Standardimplementierung verfügen, müssen weiterhin explizit implementiert werden.
Implementieren derselben Schnittstelle bei verschiedenen generischen Instanziierungen
F# unterstützt die Implementierung derselben Schnittstelle bei verschiedenen generischen Instanziierungen wie der folgenden:
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"