Signaturen (F#)

Eine Signaturdatei enthält Informationen zu den öffentlichen Signaturen eines Satzes von F#-Programmelementen, z. B. Typen, Namespaces und Module. Mit ihr kann der Zugriff auf diese Programmelemente angegeben werden.

Hinweise

Für jede F#-Codedatei kann eine Signaturdatei vorhanden sein. Diese hat den gleichen Namen wie die Codedatei, jedoch mit der Erweiterung .fsi statt .fs. Signaturdateien können auch der Kompilierungsbefehlszeile hinzugefügt werden, wenn Sie die Befehlszeile direkt verwenden. Für die Unterscheidung zwischen Codedateien und Signaturdateien werden Codedateien manchmal als Implementierungsdateien bezeichnet. In einem Projekt sollte die Signaturdatei der zugeordneten Codedatei vorausgehen.

Eine Signaturdatei beschreibt die Namespaces, Module, Typen und Member in der entsprechenden Implementierungsdatei. Mithilfe der Informationen in einer Signaturdatei geben Sie an, auf welche Teile des Codes in der entsprechenden Implementierungsdatei von Code außerhalb der Implementierungsdatei zugegriffen werden kann und welche Teile des Codes interner Code der Implementierungsdatei sind. Die Namespaces, Module und Typen in der Signaturdatei müssen eine Teilmenge der Namespaces, Module und Typen in der Implementierungsdatei sein. Abgesehen von einigen weiter unten in diesem Thema genannten Ausnahmen werden die Sprachelemente, die nicht in der Signaturdatei aufgeführt sind, als private Elemente der Implementierungsdatei betrachtet. Wenn im Projekt oder der Befehlszeile keine Signaturdatei gefunden wird, wird Standardzugriff verwendet.

Weitere Informationen über Standardzugriff Sie unter Zugriffssteuerung (F#).

In einer Signaturdatei werden die Definition der Typen und die Implementierungen der einzelnen Methoden oder Funktionen nicht wiederholt. Stattdessen verwenden Sie die Signatur für die jeweilige Methode bzw. Funktion, die als vollständige Spezifikation der von einem Modul- oder Namespacefragment implementierten Funktionalität fungiert. Die Syntax für eine Typsignatur ist mit der in abstrakten Methodendeklarationen in Schnittstellen und abstrakten Klassen verwendeten Syntax identisch. Sie wird auch von IntelliSense und dem F#-Interpreter fsi.exe dargestellt, wenn dieser eine ordnungsgemäß kompilierte Eingabe anzeigt.

Wenn die Informationen in der Typsignatur nicht ausreichen, um anzugeben, ob ein Typ versiegelt oder ein Schnittstellentyp ist, müssen Sie ein Attribut hinzufügen, das für den Compiler die Art des Typs angibt. Zu diesem Zweck verwendete Attribute werden in der folgenden Tabelle beschrieben.

Attribut

Beschreibung

[<Sealed>]

Für einen Typ, der über keine abstrakten Member verfügt oder nicht erweitert werden darf.

[<Interface>]

Für einen Typ, der eine Schnittstelle ist.

Der Compiler erzeugt einen Fehler, wenn die Attribute in der Signatur und der Deklaration in der Implementierungsdatei nicht konsistent sind.

Erstellen Sie mithilfe des Schlüsselworts val eine Signatur für einen Wert oder einen Funktionswert. Mit dem Schlüsselwort type wird eine Typsignatur eingeführt.

Sie können mit der --sig-Compileroption eine Signaturdatei generieren. Im Allgemeinen werden FSI-Dateien nicht manuell geschrieben. Stattdessen generieren Sie FSI-Dateien mit dem Compiler, fügen sie ggf. dem Projekt hinzu und bearbeiten sie, indem Sie Methoden und Funktionen entfernen, auf die kein Zugriff möglich sein soll.

Für Typsignaturen gelten mehrere Regeln:

  • Typabkürzungen in einer Implementierungsdatei dürfen keinem Typ ohne Abkürzung in einer Signaturdatei entsprechen.

  • Datensätze und Unterscheidungs-Unions müssen entweder alle eigenen Felder und Konstruktoren oder keines der eigenen Felder und Konstruktoren verfügbar machen, und die Reihenfolge in der Signatur muss mit der Reihenfolge in der Implementierungsdatei übereinstimmen. Einige, alle oder keine der Felder und Methoden von Klassen können in der Signatur offen gelegt werden.

  • Klassen und Strukturen, die über Konstruktoren verfügen, müssen die Deklarationen ihrer Basisklassen (die inherits-Deklaration) verfügbar machen. Klassen und Strukturen, die über Konstruktoren verfügen, müssen außerdem alle ihrer abstrakten Methoden und Schnittstellendeklarationen verfügbar machen.

  • Schnittstellentypen müssen alle ihre Methoden und Schnittstellen offen legen.

Für Wertsignaturen gelten folgende Regeln:

  • Zugriffsmodifizierer (public, internal usw.) sowie der inline-Modifizierer und der mutable-Modifizierer in der Signatur müssen mit den entsprechenden Modifizierern in der Implementierung übereinstimmen.

  • Die Anzahl der generischen Typparameter (implizit abgeleitet oder explizit deklariert) sowie die Typen und Typeinschränkungen in generischen Typparametern müssen übereinstimmen.

  • Wenn das Literal-Attribut verwendet wird, muss es sowohl in der Signatur als auch in der Implementierung angezeigt werden, und für beide muss der gleiche literale Wert verwendet werden.

  • Das Muster der Parameter (auch als Stelligkeit bezeichnet) von Signaturen und Implementierungen muss konsistent sein.

Das folgende Codebeispiel veranschaulicht eine Signaturdatei, die Namespace-, Modul-, Funktionswert- und Typsignaturen sowie die entsprechenden Attribute enthält. Im Beispiel wird außerdem die entsprechende Implementierungsdatei gezeigt.

// Module1.fsi

namespace Library1
  module Module1 = 
    val function1 : int -> int
    type Type1 =
        new : unit -> Type1
        member method1 : unit -> unit
        member method2 : unit -> unit

    [<Sealed>]
    type Type2 = 
        new : unit -> Type2
        member method1 : unit -> unit
        member method2 : unit -> unit

    [<Interface>]
    type InterfaceType1 =  
        abstract member method1 : int -> int
        abstract member method2 : string -> unit

Im folgenden Code wird die Implementierungsdatei veranschaulicht.

namespace Library1

module Module1 =

    let function1 x = x + 1


    type Type1() =
        member type1.method1() =
            printfn "test1.method1"
        member type1.method2() =
            printfn "test1.method2"


    [<Sealed>]
    type Type2() =
        member type2.method1() =
            printfn "test1.method1"
        member type1.method2() =
            printfn "test1.method2"

    [<Interface>]
    type InterfaceType1 =
        abstract member method1 : int -> int
        abstract member method2 : string -> unit

Siehe auch

Konzepte

Zugriffssteuerung (F#)

Weitere Ressourcen

F#-Sprachreferenz

Compileroptionen (F#)

Änderungsprotokoll

Datum

Versionsgeschichte

Grund

Mai 2010

Code für den Namespace der Signaturdatei korrigiert.

Korrektur inhaltlicher Fehler.