编译器指令

本主题介绍适用于 F# Interactive (dotnet fsi) 指令的编译器指令,请参阅 使用 F# 的交互式编程

编译器指令以 # 符号为前缀,并单独出现在行上。

下表列出了 F# 中可用的编译器指令。

Directive Description
#if if-expression 支持条件编译。 在#if的计算结果为时,包含defined节中的内容。
#else 支持条件编译。 如果上一个#if符号未计算出defined,则标记要包含的代码部分。
#endif 支持条件编译。 标记条件代码段的末尾。
#[line] int
#[line] int字符串
#[line] int逐字字符串
指示原始源代码行和文件名以用于调试。 此功能是为生成 F# 源代码的工具而提供的。
#nowarn warningcodes 禁用由 警告码 指定的一个或多个编译器警告(请参阅下文)。
#warnon warningcodes 启用由 警告码 指定的一个或多个编译器警告(请参阅下文)。

条件编译指令

由这些指令之一停用的代码会在 Visual Studio Code 编辑器中显示为灰色。

以下代码演示了 #if#else#endif 指令的用法。 在此示例中,代码包含两个版本的 function1 定义。 当 VERSION1 使用 -define 编译器选项进行定义时,会激活 #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-expr1if-expr2defined
if-expr1 && if-expr2 defined 如果 if-expr1if-expr2defined
!if-expr1 如果defined不是if-expr1,则defined
( if-expr1 ) 如果 if-expr1 已定义,则这是已定义的。
symbol defined 如果它是被-define 编译器选项标记为已定义。

逻辑运算符具有通常的逻辑优先级。

F# 中没有 #define 编译器指令。 必须使用编译器选项或项目设置来定义 #if 指令使用的符号。

条件编译指令可以进行嵌套。 对于编译器指令,缩进并不重要。

NULLABLE 指令

从 F# 9 开始,可以在项目中启用可为 null 的引用类型:

<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 指令

警告指令对源文件的某些部分禁用或启用指定的编译器警告。

警告指令是一行源代码,其中包含

  • 可选前导空格
  • 字符串 #nowarn#warnon
  • Whitespace
  • 一个或多个 警告代码 (请参阅下文),用空格分隔
  • 可选空格
  • 可选行注释

警告码 是一系列数字(表示警告编号),可能前面有 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

另请参阅