在编译期间检查代码报价结构

时间:2016-12-12 17:08:18

标签: reflection f#

我可以定义一个引用表达式参数,这样不仅表达式的结果类型是编译时检查的 还有呼叫站点表达。

让我们看一个例子:

type A = {
    a : int
}

type Checker () =
     static member Check(e : Expr<int>) : ResultType = ...

以下明显的类型检查

let a = { a = 1 }
Checker.Check <@ a.a @>

导致类似于PropertyGet( ..., PropertyGet (....), a)的实际表达式。

现在还有其他方式

let getInt (a:A) : int = a.a

以下也编译

Checker.Check <@ getInt a @>

但是,如何防止第二个示例编译并仅允许PropertyGet s? (仅作为一个例子) 我知道我可以在运行时检查表达式的结构 - 但我喜欢进行编译时检查。

1 个答案:

答案 0 :(得分:1)

正如Fyodor在评论中所说,没有办法确保报价在编译时只是某种形状。这是非常不幸的,但所有基于引用(或基于表达式)的库都受此影响(最明显的是LINQ),如果您的需求是“仅属性 - 获取者”,那么我想您可以将其作为运行时检查

如果我真的想保证这一点,我可能会尝试使用F# Compiler Service,这样可以获得typed expression tree。然后,您可以遍历树并查找项目中的所有引用并报告错误(它可以以一些可扩展的方式作为linter插件完成,其他人也可以从中受益)。

如果您进入DSL方向,那么您可以编写a |> get "foo" |> get "bar"(使用管道)或a?foo?bar(使用?运算符),但之后会丢失检查在名称上,这似乎比不能检查报价的正确形状更糟糕。