Udostępnij za pomocą


Dyrektywy kompilatora

W tym temacie opisano dyrektywy kompilatora w przypadku dyrektyw F# Interactive (dotnet fsi), zobacz Interactive Programming with F#(Programowanie interakcyjne za pomocą języka F#).

Dyrektywa kompilatora jest poprzedzona symbolem # i jest wyświetlana w samym wierszu.

W poniższej tabeli wymieniono dyrektywy kompilatora, które są dostępne w języku F#.

Directive Description
#if wyrażenie-if Obsługuje kompilację warunkową. Kod w sekcji po #if jest zawarty, jeśli wyrażenie if ocenia się na defined (zobacz poniżej).
#else Obsługuje kompilację warunkową. Oznacza sekcję kodu, która ma być uwzględniona, jeśli symbol użyty z poprzednim #if nie jest równy defined.
#endif Obsługuje kompilację warunkową. Oznacza koniec sekcji warunkowej kodu.
#[wiersz] int,
#[wiersz] ciąg int,
#[wiersz] intverbatim-string
Wskazuje oryginalny wiersz kodu źródłowego i nazwę pliku na potrzeby debugowania. Ta funkcja jest udostępniana dla narzędzi, które generują kod źródłowy języka F#.
#nowarn kody ostrzegawcze Wyłącza co najmniej jedno ostrzeżenie kompilatora określone przez kody ostrzegawcze (patrz poniżej).
#warnon kody ostrzegawcze Włącza co najmniej jedno ostrzeżenie kompilatora określone przez kody ostrzegawcze (patrz poniżej).

Dyrektywy kompilacji warunkowej

Kod dezaktywowany przez jedną z tych dyrektyw jest wyświetlany wygaszony w Edytorze programu Visual Studio Code.

Poniższy kod ilustruje użycie #ifdyrektyw , #elsei #endif . W tym przykładzie kod zawiera dwie wersje definicji function1. Gdy VERSION1 jest definiowana przy użyciu opcji -define kompilatora, kod między #if dyrektywą a dyrektywą #else jest aktywowany. W przeciwnym razie kod między elementami #else i #endif jest aktywowany.

#if VERSION1
let function1 x y =
   printfn "x: %d y: %d" x y
   x + 2 * y
#else
let function1 x y =
   printfn "x: %d y: %d" x y
   x - 2*y
#endif

let result = function1 10 20

Dyrektywa #if akceptuje również wyrażenia logiczne:

#if SILVERLIGHT || COMPILED && (NETCOREFX || !DEBUG)
#endif

Można użyć następujących wyrażeń.

wyrażenie-if ocena
if-expr1 \|\| if-expr2 defined jeśli if-expr1 lub if-expr2 jest defined.
if-expr1 && if-expr2 defined jeśli if-expr1 i if-expr2defined.
!if-expr1 defined jeśli if-expr1 nie defined.
( if-expr1 ) zdefiniowane, jeśli if-expr1 jest zdefiniowane.
symbol defined jeśli jest oznaczony jako zdefiniowany przez opcję kompilatora -define.

Operatory logiczne mają zwykły pierwszeństwo logiczne.

Nie istnieje dyrektywa kompilatora #define w języku F#. Aby zdefiniować symbole używane przez dyrektywę #if , należy użyć opcji kompilatora lub ustawień projektu.

Dyrektywy kompilacji warunkowej można zagnieżdżać. Wcięcie nie jest istotne dla dyrektyw kompilatora.

Wstępnie zdefiniowane symbole

Kompilator języka F# i system kompilacji automatycznie definiują kilka symboli, których można użyć do kompilacji warunkowej.

Symbole konfiguracji kompilacji

Następujące symbole są definiowane na podstawie konfiguracji kompilacji:

  • DEBUG: zdefiniowane podczas kompilowania w trybie debugowania. W systemie DEBUG projektu symbol jest automatycznie definiowany w konfiguracji debugowania, ale nie w konfiguracji wydania. Ten symbol jest często używany z asercji i kodu diagnostycznego. Aby uzyskać więcej informacji, zobacz Asercji.
  • TRACE: zdefiniowana dla kompilacji, które umożliwiają śledzenie. Podobnie jak DEBUG, ten symbol jest zwykle definiowany w konfiguracjach debugowania, ale można go również włączyć w konfiguracjach wydania.

Te wartości można zastąpić przy użyciu opcji kompilatora-define lub ustawień projektu.

Symbole trybu kompilacji

Następujące symbole rozróżniają różne tryby kompilacji:

  • COMPILED: zdefiniowany podczas kompilowania kodu za pomocą kompilatora języka F#. Ten symbol jest przydatny, gdy potrzebny jest kod, aby zachowywał się inaczej w skompilowanych zestawach, a w sesjach interaktywnych języka F#.
  • INTERACTIVE: zdefiniowany podczas kompilowania lub wykonywania kodu w języku F# Interactive (dotnet fsi), w tym sesji interakcyjnych i wykonywania skryptu. Dzięki temu można napisać kod, który działa inaczej podczas interakcyjnego uruchamiania.

Aby uzyskać więcej informacji na temat używania tych symboli w skryptach, zobacz Interactive Programming with F#(Programowanie interakcyjne za pomocą języka F#).

Przykład:

#if INTERACTIVE
// Code specific to F# Interactive
#r "nuget: Newtonsoft.Json"
#endif

#if COMPILED
// Code specific to compiled assemblies
open System.Configuration
#endif

Symbole platformy docelowej

System kompilacji definiuje również symbole preprocesora dla różnych platform docelowych w projektach w stylu zestawu SDK. Te symbole są przydatne podczas tworzenia bibliotek lub aplikacji przeznaczonych dla wielu wersji platformy .NET.

Platformy docelowe Symbols Dodatkowe symbole
(dostępne w zestawach SDK .NET 5+)
Symbole platformy (dostępne tylko
podczas określania formatu TFM specyficznego dla systemu operacyjnego)
.NET Framework NETFRAMEWORK, NET481, , , NET48NET472NET471NET47NET462NET461NET46NET452NET451NET45NET40NET35NET20 NET48_OR_GREATER, NET472_OR_GREATER, NET471_OR_GREATERNET47_OR_GREATERNET462_OR_GREATERNET461_OR_GREATERNET46_OR_GREATERNET452_OR_GREATERNET451_OR_GREATERNET45_OR_GREATERNET40_OR_GREATERNET35_OR_GREATERNET20_OR_GREATER
.NET Standard NETSTANDARD, NETSTANDARD2_1, , , NETSTANDARD2_0NETSTANDARD1_6NETSTANDARD1_5NETSTANDARD1_4NETSTANDARD1_3NETSTANDARD1_2NETSTANDARD1_1NETSTANDARD1_0 NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, , NETSTANDARD1_6_OR_GREATER, NETSTANDARD1_5_OR_GREATERNETSTANDARD1_4_OR_GREATER, NETSTANDARD1_3_OR_GREATER, , NETSTANDARD1_2_OR_GREATERNETSTANDARD1_1_OR_GREATERNETSTANDARD1_0_OR_GREATER
.NET 5+ (i .NET Core) NET, NET10_0, , , NET9_0NET8_0NET7_0NET6_0NET5_0NETCOREAPPNETCOREAPP3_1NETCOREAPP3_0NETCOREAPP2_2NETCOREAPP2_1NETCOREAPP2_0NETCOREAPP1_1NETCOREAPP1_0 NET10_0_OR_GREATER, NET9_0_OR_GREATER, NET8_0_OR_GREATERNET7_0_OR_GREATERNET6_0_OR_GREATERNET5_0_OR_GREATERNETCOREAPP3_1_OR_GREATERNETCOREAPP3_0_OR_GREATERNETCOREAPP2_2_OR_GREATERNETCOREAPP2_1_OR_GREATERNETCOREAPP2_0_OR_GREATERNETCOREAPP1_1_OR_GREATERNETCOREAPP1_0_OR_GREATER ANDROID, BROWSER, , IOS, MACCATALYSTMACOS, , TVOS, , WINDOWS
[OS][version] (na przykład IOS15_1),
[OS][version]_OR_GREATER (na przykład IOS15_1_OR_GREATER)

Uwaga / Notatka

  • Symbole bez wersji są definiowane niezależnie od wersji, na którą są kierowane.
  • Symbole specyficzne dla wersji są definiowane tylko dla docelowej wersji.
  • Symbole <framework>_OR_GREATER są definiowane dla docelowej wersji i wszystkich wcześniejszych wersji. Jeśli na przykład celem jest .NET Framework 2.0, zdefiniowane są następujące symbole: NET20, NET20_OR_GREATER, NET11_OR_GREATER i NET10_OR_GREATER.
  • Symbole NETSTANDARD<x>_<y>_OR_GREATER są definiowane tylko dla obiektów docelowych platformy .NET Standard, a nie dla obiektów docelowych implementujących platformę .NET Standard, takich jak .NET Core i .NET Framework.
  • Różnią się one od identyfikatorów frameworku docelowego (TFMs) używanych przez właściwość MSBuild i NuGet.

Na przykład można użyć tych symboli do warunkowego skompilowania kodu na podstawie platformy docelowej:

#if NET6_0_OR_GREATER
// Use .NET 6+ specific APIs
#else
// Use alternative implementation for older frameworks
#endif

Dyrektywa NULLABLE

Począwszy od F# 9, można włączyć typy referencyjne dopuszczające wartości null w projekcie.

<Nullable>enable</Nullable>

Spowoduje to automatyczne przypisanie do build dyrektywy NULLABLE. Jest to przydatne podczas początkowego wdrażania funkcji, aby warunkowo zmodyfikować konfliktowy kod za pomocą dyrektyw z hashem #if NULLABLE.

#if NULLABLE 
let length (arg: 'T when 'T: not null) =
    Seq.length arg
#else
let length arg =
    match arg with
    | null -> -1
    | s -> Seq.length s
#endif

Dyrektywy liniowe

Podczas kompilowania kompilator zgłasza błędy w kodzie języka F#, odwołując się do numerów wierszy, w których wystąpi każdy błąd. Te numery wierszy zaczynają się od 1 dla pierwszego wiersza w pliku. Jeśli jednak generujesz kod źródłowy języka F# z innego narzędzia, numery wierszy wygenerowanego kodu zwykle nie są interesujące, ponieważ błędy wygenerowanego kodu F# najprawdopodobniej wynikają z innego źródła. Dyrektywa #line zapewnia autorom narzędzi, które generują kod źródłowy języka F# w celu przekazywania informacji o oryginalnych numerach wierszy i plikach źródłowych do wygenerowanego kodu F#.

W przypadku korzystania z #line dyrektywy nazwy plików muszą być ujęte w cudzysłów. Chyba że token dosłowny (@) pojawia się przed ciągiem, należy użyć dwóch znaków ukośnika odwrotnego zamiast jednego, aby używać ich w ścieżce. Poniżej przedstawiono prawidłowe tokeny wiersza. W tych przykładach przyjęto założenie, że oryginalny plik Script1 powoduje automatyczne wygenerowanie pliku kodu F# podczas jego uruchamiania za pomocą narzędzia i że kod w lokalizacji tych dyrektyw jest generowany na podstawie niektórych tokenów w wierszu 25 w pliku Script1.

# 25
#line 25
#line 25 "C:\\Projects\\MyProject\\MyProject\\Script1"
#line 25 @"C:\Projects\MyProject\MyProject\Script1"
# 25 @"C:\Projects\MyProject\MyProject\Script1"

Te tokeny wskazują, że kod języka F# wygenerowany w tej lokalizacji pochodzi z niektórych konstrukcji znajdujących się w wierszu lub w pobliżu 25 .Script1

Należy zauważyć, że #line dyrektywy nie mają wpływu na zachowanie #nowarn / #warnon. Te dwie dyrektywy zawsze odnoszą się do skompilowanego pliku.

Ostrzegaj dyrektywy

Dyrektywy 'warn' wyłączają lub włączają określone ostrzeżenia kompilatora dla części pliku źródłowego.

Dyrektywa ostrzegawcze jest pojedynczym wierszem kodu źródłowego, który składa się z

  • Opcjonalne białe znaki wiodące
  • Ciąg #nowarn lub #warnon
  • Whitespace
  • Co najmniej jeden kod ostrzegawczy (patrz poniżej) oddzielony białym znakiem
  • Opcjonalne odstępy
  • Opcjonalny komentarz wiersza

Kod ostrzegawczy to sekwencja cyfr (reprezentująca numer ostrzeżenia), opcjonalnie poprzedzona FSznakiem , opcjonalnie otoczona podwójnymi cudzysłowami.

Dyrektywa #nowarn wyłącza ostrzeżenie, chyba że zostanie znaleziona dyrektywa #warnon dla tego samego numeru ostrzeżenia lub do końca pliku. #nowarn Podobnie dyrektywa wyłącza ostrzeżenie do momentu #warnon znalezienia dyrektywy dla tego samego numeru ostrzeżenia lub do końca pliku. Przed i po takich parach zastosowanie ma ustawienie domyślne kompilacji, czyli

  • brak ostrzeżenia, jeśli jest wyłączone przez opcję kompilatora --nowarn (lub odpowiednią właściwość msbuild)
  • brak ostrzeżeń dla ostrzeżeń związanych z wyrażeniem zgody, chyba że włączono opcję kompilatora --warnon (lub odpowiednią właściwość msbuild)

Oto przykład (spisany).

module A
match None with None -> ()     // warning
let x =
    #nowarn 25
    match None with None -> 1  // no warning
    #warnon FS25
match None with None -> ()     // warning
#nowarn "FS25" FS007 "42"
match None with None -> ()     // no warning

Zobacz także