Podpisy

Plik podpisu zawiera informacje o podpisach publicznych zestawu elementów programu języka F#, takich jak typy, przestrzenie nazw i moduły. Może służyć do określania ułatwień dostępu tych elementów programu.

Uwagi

Dla każdego pliku kodu F# można mieć plik podpisu, który jest plikiem o takiej samej nazwie jak plik kodu, ale z rozszerzeniem fsi zamiast .fsi. Pliki podpisów można również dodać do wiersza polecenia kompilacji, jeśli używasz wiersza polecenia bezpośrednio. Aby odróżnić pliki kodu i pliki sygnatur, pliki kodu są czasami nazywane plikami implementacji. W projekcie plik podpisu powinien poprzedzać skojarzony plik kodu.

Plik podpisu opisuje przestrzenie nazw, moduły, typy i elementy członkowskie w odpowiednim pliku implementacji. Informacje w pliku podpisu służą do określenia, do jakich części kodu w odpowiednim pliku implementacji można uzyskać dostęp z kodu spoza pliku implementacji oraz części wewnętrznego pliku implementacji. Przestrzenie nazw, moduły i typy zawarte w pliku podpisu muszą być podzbiorem przestrzeni nazw, modułów i typów uwzględnionych w pliku implementacji. W przypadku niektórych wyjątków zanotowanych w dalszej części tego tematu te elementy języka, które nie są wymienione w pliku podpisu, są uznawane za prywatne dla pliku implementacji. Jeśli w projekcie lub wierszu polecenia nie znaleziono pliku podpisu, zostanie użyta domyślna dostępność.

Aby uzyskać więcej informacji na temat domyślnej ułatwień dostępu, zobacz Kontrola dostępu.

W pliku podpisu nie powtarzasz definicji typów i implementacji każdej metody lub funkcji. Zamiast tego należy użyć podpisu dla każdej metody i funkcji, która działa jako pełna specyfikacja funkcji implementowana przez moduł lub fragment przestrzeni nazw. Składnia podpisu typu jest taka sama jak ta używana w abstrakcyjnych deklaracjach metod w interfejsach i klasach abstrakcyjnych, a także jest wyświetlana przez funkcję IntelliSense i przez interpreter języka F# fsi.exe, gdy wyświetla poprawnie skompilowane dane wejściowe.

Jeśli w podpisie typu nie ma wystarczającej ilości informacji, aby wskazać, czy typ jest zapieczętowany, czy jest to typ interfejsu, należy dodać atrybut wskazujący charakter typu kompilatora. Atrybuty używane w tym celu zostały opisane w poniższej tabeli.

Atrybut opis
[<Sealed>] W przypadku typu, który nie ma abstrakcyjnych elementów członkowskich lub które nie powinny być rozszerzone.
[<Interface>] Dla typu, który jest interfejsem.

Kompilator generuje błąd, jeśli atrybuty nie są spójne między podpisem a deklaracją w pliku implementacji.

Użyj słowa kluczowego val , aby utworzyć podpis dla wartości lub wartości funkcji. Słowo kluczowe type wprowadza podpis typu.

Plik podpisu można wygenerować przy użyciu opcji kompilatora --sig . Ogólnie rzecz biorąc, pliki fsi nie są zapisywane ręcznie. Zamiast tego wygenerujesz pliki fsi przy użyciu kompilatora, dodaj je do projektu, jeśli go masz, a następnie edytujesz je, usuwając metody i funkcje, które nie mają być dostępne.

Istnieje kilka reguł dotyczących podpisów typów:

  • Skróty typów w pliku implementacji nie mogą być zgodne z typem bez skrótu w pliku podpisu.

  • Rekordy i związki dyskryminowane muszą uwidocznić wszystkie lub żadne z ich pól i konstruktorów, a kolejność w podpisie musi być zgodna z kolejnością w pliku implementacji. Klasy mogą ujawniać niektóre, wszystkie lub żadne z ich pól i metod w podpisie.

  • Klasy i struktury, które mają konstruktory, muszą uwidocznić deklaracje ich klas bazowych (deklaracji inherits ). Ponadto klasy i struktury, które mają konstruktory, muszą uwidocznić wszystkie ich abstrakcyjne metody i deklaracje interfejsu.

  • Typy interfejsów muszą ujawniać wszystkie metody i interfejsy.

Reguły dotyczące podpisów wartości są następujące:

  • Modyfikatory ułatwień dostępu (publicitd internal.) oraz inline modyfikatory i mutable w podpisie muszą być zgodne z elementami w implementacji.

  • Liczba parametrów typu ogólnego (niejawnie wywnioskowanych lub jawnie zadeklarowanych) musi być zgodna, a typy i ograniczenia typu w parametrach typu ogólnego muszą być zgodne.

  • Literal Jeśli atrybut jest używany, musi być wyświetlany zarówno w podpisie, jak i implementacji, a ta sama wartość literału musi być używana dla obu tych elementów.

  • Wzorzec parametrów (nazywany również arity) podpisów i implementacji musi być spójny.

  • Jeśli nazwy parametrów w pliku podpisu różnią się od odpowiedniego pliku implementacji, nazwa w pliku podpisu zostanie użyta, co może powodować problemy podczas debugowania lub profilowania. Jeśli chcesz otrzymywać powiadomienia o takich niezgodnościach, włącz ostrzeżenie 3218 w pliku projektu lub podczas wywoływania kompilatora (zobacz --warnon w obszarze Opcje kompilatora).

Poniższy przykład kodu przedstawia przykład pliku podpisu, który zawiera przestrzeń nazw, moduł, wartość funkcji i podpisy typu wraz z odpowiednimi atrybutami. Pokazuje również odpowiedni plik implementacji.

// 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

Poniższy kod przedstawia plik implementacji.

namespace Library1

module Module1 =

    let function1 x = x + 1


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


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

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

Zobacz też