本主題描述編譯程式指示詞,適用於 F# Interactive (dotnet fsi) 指示詞,請參閱 使用 F# 進行互動式程式設計。
編譯程式指示詞前面會加上 # 符號,並單獨出現在行上。
下表列出 F# 中可用的編譯程式指示詞。
| Directive | Description |
|---|---|
#if
if運算式 |
支援條件式編譯。
#if區段中的程式代碼將被包含在內,如果if-expression的評估結果為defined。 |
#else |
支援條件式編譯。 如果與前面的 #if 一起使用的符號不評估為 defined,則標記代碼區段以包含。 |
#endif |
支援條件式編譯。 標示程式碼的條件式區段結尾。 |
#[line] int,#[line] intstring,#[line] int逐字字串 |
表示原始的原始程式碼行和檔案名稱 (適用於偵錯)。 這項功能提供用於產生 F# 原始程式碼的工具。 |
#nowarn
警告代碼 |
停用一或多個編譯程式警告,如 warningcodes 所指定(請參閱下文)。 |
#warnon
警告代碼 |
啟用一或多個編譯程式警告,如 warningcodes 所指定(請參閱下文)。 |
條件式編譯指示詞
由上述其中一個指示詞停用的程式碼會在 Visual Studio 程式碼編輯器中顯示為停用。
下列程式碼說明如何使用 #if、#else 和 #endif 指示詞。 在此範例中,程式碼包含兩個版本的 function1 定義。 使用 VERSION1定義 時,會啟用 #if 指示詞與 #else 指示詞之間的程式碼。 否則會啟動 #else 與 #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
指令 #if 也接受邏輯運算式:
#if SILVERLIGHT || COMPILED && (NETCOREFX || !DEBUG)
#endif
您可以使用下列表示式。
| if-expr | 評估 |
|---|---|
if-expr1 \|\| if-expr2 |
defined 如果 if-expr1 或 if-expr2 為 ,則為 defined。 |
if-expr1 && if-expr2 |
defined 如果 if-expr1 與 if-expr2 為 ,則為 defined。 |
!if-expr1 |
defined 如果if-expr1不是defined。 |
( if-expr1 ) |
若 if-expr1 被定義,則其已定義。 |
symbol |
defined 如果它被-define編譯器選項定義為標記,則如此。 |
邏輯運算元具有一般邏輯優先順序。
F# 中沒有 #define 編譯程式指示詞。 您必須使用編譯器選項或專案設定來定義 #if 指示詞所使用的符號。
條件式編譯指示詞可以巢狀化。 縮排對於編譯器指令來說並不重要。
預先定義的符號
F# 編譯器和建置系統會自動定義數個可用於條件式編譯的符號。
建置組態符號
下列符號是根據您的組建組態來定義:
-
DEBUG:在偵錯模式下編譯時定義。 在專案系統中,DEBUG符號會自動在偵錯組態中定義,但不會在發行組態中自動定義。 此符號通常與判斷提示和診斷程式碼一起使用。 如需詳細資訊,請參閱 宣告。 -
TRACE:針對啟用追蹤的組建定義。 與DEBUG一樣,此符號通常在偵錯配置中定義,但也可以在版本配置中啟用。
您可以使用編譯器選項或專案設定來-define覆寫這些值。
編譯模式符號
下列符號區分不同的編譯模式:
-
COMPILED:使用 F# 編譯器編譯程式碼時所定義。 當您需要程式碼在編譯元件與 F# 互動式會話中以不同的方式運作時,此符號很有用。 -
INTERACTIVE:在 F# Interactive ()dotnet fsi中編譯或執行程式碼時所定義,包括互動式工作階段和腳本執行。 這可讓您撰寫在互動式執行時以不同方式運作的程式碼。
如需在腳本中使用這些符號的詳細資訊,請參閱 使用 F# 互動式程式設計。
範例:
#if INTERACTIVE
// Code specific to F# Interactive
#r "nuget: Newtonsoft.Json"
#endif
#if COMPILED
// Code specific to compiled assemblies
open System.Configuration
#endif
目標架構符號
建置系統也會定義 SDK 樣式專案中不同目標架構的前置處理器符號。 這些符號在建立以多個 .NET 版本為目標的程式庫或應用程式時很有用。
| 目標框架 | 符號 | 其他符號 (適用於 .NET 5+ SDK) |
平台符號(僅可用於特定情境) 當您指定作業系統特定的 TFM 時 |
|---|---|---|---|
| .NET Framework |
NETFRAMEWORK、NET481、NET48、NET472、NET471、NET47、NET462、NET461、NET46、NET452、NET451、NET45、NET40、NET35、NET20 |
NET48_OR_GREATER、NET472_OR_GREATER、NET471_OR_GREATER、NET47_OR_GREATER、NET462_OR_GREATER、NET461_OR_GREATER、NET46_OR_GREATER、NET452_OR_GREATER、NET451_OR_GREATER、NET45_OR_GREATER、NET40_OR_GREATER、NET35_OR_GREATER、NET20_OR_GREATER |
|
| .NET Standard |
NETSTANDARD、NETSTANDARD2_1、NETSTANDARD2_0、NETSTANDARD1_6、NETSTANDARD1_5、NETSTANDARD1_4、NETSTANDARD1_3、NETSTANDARD1_2、NETSTANDARD1_1、NETSTANDARD1_0 |
NETSTANDARD2_1_OR_GREATER、NETSTANDARD2_0_OR_GREATER、NETSTANDARD1_6_OR_GREATER、NETSTANDARD1_5_OR_GREATER、NETSTANDARD1_4_OR_GREATER、NETSTANDARD1_3_OR_GREATER、NETSTANDARD1_2_OR_GREATER、NETSTANDARD1_1_OR_GREATER、NETSTANDARD1_0_OR_GREATER |
|
| .NET 5+ (和 .NET Core) |
NET、NET10_0、NET9_0、NET8_0、NET7_0、NET6_0、NET5_0、NETCOREAPP、NETCOREAPP3_1、NETCOREAPP3_0、NETCOREAPP2_2、NETCOREAPP2_1、NETCOREAPP2_0、NETCOREAPP1_1、NETCOREAPP1_0 |
NET10_0_OR_GREATER、NET9_0_OR_GREATER、NET8_0_OR_GREATER、NET7_0_OR_GREATER、NET6_0_OR_GREATER、NET5_0_OR_GREATER、NETCOREAPP3_1_OR_GREATER、NETCOREAPP3_0_OR_GREATER、NETCOREAPP2_2_OR_GREATER、NETCOREAPP2_1_OR_GREATER、NETCOREAPP2_0_OR_GREATER、NETCOREAPP1_1_OR_GREATER、NETCOREAPP1_0_OR_GREATER |
ANDROID、BROWSER、IOS、MACCATALYST、MACOS、TVOS、、、 WINDOWS[OS][version] (例如 IOS15_1)、[OS][version]_OR_GREATER (例如 IOS15_1_OR_GREATER) |
備註
- 無論您的目標版本為何,系統都會定義無版本符號。
- 系統只會針對您設定為目標的版本定義版本特定符號。
- 系統會針對您的目標版本和所有更早版本定義
<framework>_OR_GREATER符號。 舉例來說,如果您要以 .NET Framework 2.0 為目標,則會定義下列符號:NET20、NET20_OR_GREATER、NET11_OR_GREATER與NET10_OR_GREATER。 -
NETSTANDARD<x>_<y>_OR_GREATER符號只會針對 .NET Standard 目標定義,而不是針對實作 .NET Standard 的目標,例如 .NET Core 和 .NET Framework。 - 這些與 MSBuild
TargetFramework屬性和 NuGet 使用的目標框架標記不同。
例如,您可以使用這些符號,根據目標架構有條件地編譯程式碼:
#if NET6_0_OR_GREATER
// Use .NET 6+ specific APIs
#else
// Use alternative implementation for older frameworks
#endif
NULLABLE 指示詞
從 F# 9 開始,您可以在專案中啟用可空的參考類型。
<Nullable>enable</Nullable>
這會自動將 NULLABLE 指令設定為建置。 在一開始推出此功能時,最好透過 #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
行指示詞
建置時,編譯器會參考發生的每個錯誤所在的行號,以報告 F# 程式碼中的錯誤。 這些行號從 1 開始,從檔案的第一行起算。 不過,如果您正在從另一個工具產生 F# 原始程式碼,產生的程式碼中的行號通常不重要,因為產生的 F# 程式碼中的錯誤很可能來自其他來源。
#line 指示詞為工具的作者提供一種方式,即產生 F# 原始程式碼,將有關原始行號和來源檔案的相關資訊傳遞給產生的 F# 程式碼。
使用 #line 指示詞時,檔案名稱必須括在引號內。 除非逐字語彙基元 (@) 會出現在字串前面,否則必須逸出反斜線字元 (使用兩個反斜線字元而非一個),才能在路徑中使用它們。 下面是有效的行語彙基元。 在這些範例中,假設透過工具執行原始檔案 Script1 時,會自動產生 F# 程式碼檔案,並會在 Script1 檔的第 25 行,從某些語彙基元中產生這些指示詞位置處的程式碼。
# 25
#line 25
#line 25 "C:\\Projects\\MyProject\\MyProject\\Script1"
#line 25 @"C:\Projects\MyProject\MyProject\Script1"
# 25 @"C:\Projects\MyProject\MyProject\Script1"
這些語彙基元指出在這個位置產生的 F# 程式碼,是衍生自 25 的 Script1 行或附近的某些建構。
請注意,#line 指示詞不會影響#nowarn / #warnon 的行為。 這兩個指示詞一律會關聯正在編譯的檔案。
Warn 指示詞
警告指示詞會停用或啟用來源檔案部分的指定編譯程式警告。
warn 指示詞是由單一行原始程式碼組成的
- 選擇性前置空格符
- 字串
#nowarn或#warnon - Whitespace
- 一或多個 警告碼 (如下所示),以空格符分隔
- 選擇性空格符
- 選擇性行註解
warningcode 是一連串的數位(代表警告編號),在 前面FS選擇性地以雙引號括住。
#nowarn 指令會停用警告,直到遇到相同警告編號的 #warnon 指令,或直到檔案結尾。 同樣地,#nowarn 指示詞會停用警告,直到出現針對相同警告編號的 #warnon 指示詞,或到達文件結尾為止。 在這類配對前後,會套用編譯預設值,也就是
- 若已透過 --nowarn 編譯選項或相應的 msbuild 屬性停用,則不會發出警告。
- 除非啟用了 --warnon 編譯器選項(或相應的 msbuild 屬性),否則不會針對選擇性警告發出任何警告。
以下是(刻意)的範例。
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