如何在 F# 中有条件地内联成员,或完全关闭调试构建中的内联

How to conditionally inline members in F#, or switch off inlining in Debug builds altogether

我不太记得是在哪里读到的,但我对内联的理解是在调试构建期间它是 "switched off"(静态解析类型约束除外)。但事实并非如此,内联成员上的断点永远不会命中,并且 进入 是不可能的。

由于使用内联和不使用内联之间存在(轻微的)语义差异,也许这就是在调试版本中也强制执行内联的原因?对于我确实想在调试期间调查的内联函数,我目前使用的是这样的东西:

原代码:

type CE =
    static member inline map f = CE.bind (f >> Some)   // line is never hit

更新代码

type CE =
    static member 
#if !DEBUG
            inline 
#endif
                map f =
        CE.bind (f >> Some)    // gets hit now when debugging

虽然这有效,但它很丑陋。是否有另一种可能性,即使用编译器开关或属性来转换此 on/off,或者是否要求太多麻烦(即前面提到的静态解析类型参数,也许是用户定义的自动内联运算符)。

注意:我的主要用例本身实际上不是调试,而是函数或成员的命中计数,取而代之的是代码覆盖率报告。

使用 F# 4.0、.NET 4.5 和 Visual Studio 2015。

在某些情况下,不遵循内联指令确实存在问题。正如您在问题中指出的那样,F# 核心库提供函数,包括 (+) operator, which require the use of statically-resolved type parameters。 CLR 的泛型运行时系统不支持这些类型的泛型。相反,F# 编译器在编译时推断泛型类型参数,并创建执行每个已解析类型所需的 IL。

这是一个关键特性,它使得忽略所有 inline 指令成为一般的非启动器,因为在许多情况下这意味着代码将无法编译。 --nooptimizationdata 通常从生成的程序集中删除优化数据;它不会阻止在程序集中内联,但它可能会在引用 inline 函数时阻止其他程序集内联。

还应注意,Don Syme 指出 inline 的使用并不经常需要(在 SRTP 之外)并且可能是过早的性能优化,实际上可能会妨碍编译器进行自己的优化。