Condividi tramite


Direttive del compilatore

Questo argomento descrive le direttive del compilatore, per le direttive F# Interactive (dotnet fsi), vedere Programmazione interattiva con F#.

Una direttiva del compilatore è preceduta dal simbolo # e viene visualizzata su una riga in modo autonomo.

Nella tabella seguente sono elencate le direttive del compilatore disponibili in F#.

Directive Description
#if if-expression Supporta la compilazione condizionale. Il codice nella sezione successiva a #if è incluso se l'if-expression viene valutata come defined (vedere di seguito).
#else Supporta la compilazione condizionale. Contrassegna una sezione di codice da includere se il simbolo usato con il precedente #if non restituisce defined.
#endif Supporta la compilazione condizionale. Contrassegna la fine di una sezione condizionale di codice.
#[riga] int,
#[riga] intstring,
#[riga] intverbatim-string
Indica la riga e il nome di file del codice sorgente originale per il debug. Questa funzionalità viene fornita per gli strumenti che generano codice sorgente F#.
#nowarn warningcodes Disabilita uno o più avvisi del compilatore come specificato da warningcodes (vedere di seguito).
#warnon warningcodes Abilita uno o più avvisi del compilatore come specificato dai codici di avviso (vedere di seguito).

Direttive di compilazione condizionale

Il codice disattivato da una di queste direttive viene visualizzato in grigio nell'editor di Visual Studio Code.

Nel codice di esempio che segue viene illustrato l'uso delle direttive #if, #else e #endif. In questo esempio, il codice contiene due versioni della definizione di function1. Quando VERSION1 viene definito usando l'opzione del compilatore -define, viene attivato il codice tra la #if direttiva e la #else direttiva . In caso contrario, viene attivato il codice tra #else e #endif.

#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

La #if direttiva accetta anche espressioni logiche:

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

È possibile usare le espressioni seguenti.

if-expr evaluation
if-expr1 \|\| if-expr2 defined se if-expr1 o if-expr2 è defined.
if-expr1 && if-expr2 defined se if-expr1 e if-expr2 sono defined.
!if-expr1 defined se if-expr1 non è defined.
( if-expr1 ) definito se if-expr1 è definito.
symbol defined se è contrassegnato come definito dall'opzione del -define compilatore.

Gli operatori logici hanno la consueta precedenza logica.

Non esiste alcuna #define direttiva del compilatore in F#. È necessario usare l'opzione del compilatore o le impostazioni di progetto per definire i simboli usati per la direttiva #if.

Le direttive di compilazione condizionale possono essere annidate. Il rientro non influenza le direttive del compilatore.

Simboli predefiniti

Il compilatore F# e il sistema di compilazione definiscono automaticamente diversi simboli che possono essere usati per la compilazione condizionale.

Simboli di configurazione della compilazione

I simboli seguenti vengono definiti in base alla configurazione di compilazione:

  • DEBUG: definito durante la compilazione in modalità debug. Nel sistema del progetto il DEBUG simbolo viene definito automaticamente nella configurazione debug, ma non nella configurazione release. Questo simbolo viene comunemente usato con asserzioni e codice di diagnostica. Per altre informazioni, vedere Asserzioni.
  • TRACE: definito per le compilazioni che abilitano la traccia. Come DEBUG, questo simbolo viene in genere definito nelle configurazioni di debug, ma può essere abilitato anche nelle configurazioni di rilascio.

È possibile eseguire l'override di questi valori usando l'opzione del compilatore o le impostazioni del-define progetto.

Simboli della modalità di compilazione

I simboli seguenti distinguono tra diverse modalità di compilazione:

  • COMPILED: definito durante la compilazione del codice con il compilatore F#. Questo simbolo è utile quando è necessario che il codice si comporti in modo diverso negli assembly compilati rispetto alle sessioni interattive F#.
  • INTERACTIVE: definito durante la compilazione o l'esecuzione di codice in F# Interactive (dotnet fsi), incluse le sessioni interattive e l'esecuzione di script. In questo modo è possibile scrivere codice che funziona in modo diverso quando si esegue in modo interattivo.

Per altre informazioni sull'uso di questi simboli negli script, vedere Programmazione interattiva con F#.

Esempio:

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

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

Simboli del framework di destinazione

Il sistema di compilazione definisce anche i simboli del preprocessore per framework di destinazione diversi nei progetti in stile SDK. Questi simboli sono utili quando si creano librerie o applicazioni destinate a più versioni .NET.

Framework di destinazione Simboli Simboli aggiuntivi
(disponibile in .NET 5+ SDK)
Simboli della piattaforma (disponibile solo
quando si specifica un TFM specifico del sistema operativo)
.NET Framework NETFRAMEWORK, , , , NET481NET48NET472NET471NET47NET462NET461NET46NET452NET451NET45NET40NET35NET20 NET48_OR_GREATER NET471_OR_GREATER, NET472_OR_GREATER, NET47_OR_GREATER, NET462_OR_GREATER, NET461_OR_GREATER, NET46_OR_GREATER, NET452_OR_GREATERNET451_OR_GREATER, , NET45_OR_GREATERNET40_OR_GREATER, , NET35_OR_GREATERNET20_OR_GREATER
.NET Standard NETSTANDARD NETSTANDARD2_0, NETSTANDARD2_1, , NETSTANDARD1_6, NETSTANDARD1_5NETSTANDARD1_4, NETSTANDARD1_3, NETSTANDARD1_2, , NETSTANDARD1_1NETSTANDARD1_0 NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, NETSTANDARD1_6_OR_GREATER, NETSTANDARD1_5_OR_GREATER, NETSTANDARD1_4_OR_GREATERNETSTANDARD1_3_OR_GREATER, NETSTANDARD1_2_OR_GREATER, , NETSTANDARD1_1_OR_GREATERNETSTANDARD1_0_OR_GREATER
.NET 5+ (e .NET Core) NET, , , , NET10_0NET9_0NET8_0NET7_0NET6_0NET5_0NETCOREAPPNETCOREAPP3_1NETCOREAPP3_0NETCOREAPP2_2NETCOREAPP2_1NETCOREAPP2_0NETCOREAPP1_1NETCOREAPP1_0 NET10_0_OR_GREATER NET8_0_OR_GREATER, NET9_0_OR_GREATER, NET7_0_OR_GREATER, NET6_0_OR_GREATER, NET5_0_OR_GREATER, NETCOREAPP3_1_OR_GREATER, NETCOREAPP3_0_OR_GREATERNETCOREAPP2_2_OR_GREATER, , NETCOREAPP2_1_OR_GREATERNETCOREAPP2_0_OR_GREATER, , NETCOREAPP1_1_OR_GREATERNETCOREAPP1_0_OR_GREATER ANDROID, BROWSER, IOS, MACCATALYST, MACOS, TVOS, WINDOWS
[OS][version] (ad esempio IOS15_1),
[OS][version]_OR_GREATER (ad esempio, IOS15_1_OR_GREATER)

Annotazioni

  • I simboli senza versione vengono definiti indipendentemente dalla versione di destinazione.
  • I simboli specifici della versione sono definiti solo per la versione di destinazione.
  • I simboli <framework>_OR_GREATER sono definiti per la versione di destinazione e per tutte le versioni precedenti. Ad esempio, se si ha come destinazione .NET Framework 2.0, vengono definiti i simboli seguenti: NET20, NET20_OR_GREATER, NET11_OR_GREATER e NET10_OR_GREATER.
  • I simboli NETSTANDARD<x>_<y>_OR_GREATER sono definiti solo per le destinazioni .NET Standard e non per le destinazioni che implementano .NET Standard, ad esempio .NET Core e .NET Framework.
  • Questi sono diversi dai moniker del framework di destinazione (TFMs) usati dalla proprietà TargetFramework MSBuild e da NuGet.

Ad esempio, è possibile usare questi simboli per compilare in modo condizionale il codice in base al framework di destinazione:

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

Direttiva NULLABLE

A partire da F# 9, è possibile abilitare i tipi di riferimento nullable nel progetto.

<Nullable>enable</Nullable>

In questo modo, la direttiva NULLABLE viene impostata automaticamente nella compilazione. Per modificare in modo condizionale il codice in conflitto durante l'implementazione iniziale della funzionalità, è utile utilizzare le direttive hash #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

Direttive Line

Durante la compilazione, il compilatore segnala errori nel codice F# facendo riferimento ai numeri di riga in cui si verifica ogni errore. Questi numeri di riga iniziano da 1 per la prima riga in un file. Tuttavia, se si genera codice sorgente F# da un altro strumento, i numeri di riga nel codice generato non sono generalmente di interesse, perché nel codice F# generato probabilmente gli errori sono causati da un'altra origine. La direttiva #line consente agli autori di strumenti che generano codice sorgente F# di passare le informazioni relative ai numeri di riga e ai file di origine originali al codice F# generato.

Quando si usa la direttiva #line, i nomi di file devono essere racchiusi tra virgolette. A meno che il token verbatim (@) venga visualizzato all'inizio della stringa, è necessario eseguire l'escape dei caratteri barra rovesciata usando due barre rovesciate anziché una per poterli usare nel percorso. Di seguito sono riportati dei token di riga validi. In questi esempi si presuppone che il file originale Script1 risulti in un file di codice F# generato automaticamente quando viene eseguito tramite uno strumento e che il codice nella posizione di tali direttive venga generato dagli stessi token alla riga 25 nel file Script1.

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

Questi token indicano che il codice F# generato in questa posizione è derivato da alcuni costrutti alla riga o vicino alla riga 25 in Script1.

Si noti che #line le direttive non influiscono sul comportamento di#nowarn / #warnon . Queste due direttive riguardano sempre il file che viene compilato.

Direttive Di avviso

Le direttive Warn disabilitano o abilitano gli avvisi del compilatore specificati per parti di un file di origine.

Una direttiva di avviso è una singola riga di codice sorgente costituita da

  • Spazi vuoti iniziali facoltativi
  • Stringa #nowarn o #warnon
  • Whitespace
  • Uno o più codici di avviso (vedere di seguito), separati da spazi vuoti
  • Spazi vuoti facoltativi
  • Commento riga facoltativo

Un warningcode è una sequenza di cifre (che rappresenta il numero di avviso), facoltativamente preceduto da FS, racchiuso facoltativamente tra virgolette doppie.

Una #nowarn direttiva disabilita un avviso fino a quando non viene trovata una #warnon direttiva per lo stesso numero di avviso oppure fino alla fine del file. Analogamente, una #nowarn direttiva disabilita un avviso finché non viene trovata una #warnon direttiva per lo stesso numero di avviso oppure fino alla fine del file. Prima e dopo tali coppie, viene applicata l'impostazione predefinita di compilazione, ovvero

  • nessun avviso se disabilitato da un'opzione del compilatore --nowarn (o la rispettiva proprietà msbuild)
  • nessun avviso per gli avvisi di consenso, a meno che non sia abilitato dall'opzione del compilatore --warnon (o dalla rispettiva proprietà msbuild)

Di seguito è riportato un esempio artificiale.

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

Vedere anche