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 (
public
itdinternal
.) orazinline
modyfikatory imutable
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