如何包装F#类型以访问其属性

时间:2018-06-14 15:46:03

标签: f# quotations

我不知道这是不是一个模式,所以不知道从哪里开始寻找。我会尝试解释我想要的东西。

给定带有成员Bar和Baz的类型Foo,我可以创建一个包装类型A<Foo>,它返回一个模拟实例Foo,以便我可以编写A<Foo>.Bar ...吗?目标是它可以在引文中使用,例如<@ A<Foo>.Bar > 1 @>

要清楚。如何实施A

2 个答案:

答案 0 :(得分:4)

是的,这是一种模式。

如果您正在以某种方式分析Foo的属性,请使用类型Expr<Foo -> 'a>的代码引用,如下所示:

let q = <@ fun (foo: Foo) -> foo.Bar @>

如果从上下文中知道报价的类型,您可以省略类型注释: Foo

let q : Expr<Foo -> 'a> = <@ fun foo -> foo.Bar @>

许多库以这种方式使用引号,包括query计算表达式和我最喜欢的一个Argu,一个用于解析命令行参数的库。

答案 1 :(得分:2)

有可能使用类型提供程序完全按照您的要求执行操作,但这可能会比它的价值更多。在你的情况下,我只会使用像Foq这样的模拟框架,或者如果用例很简单,只需使用对象表达式:

type Foo =
    abstract member Bar: int

let mockFoo = 
    {new Foo with
        member __.Bar = 1
    }

这是一个与您正在寻找使用Foq的内容相近的例子:

open Foq

type A<'a when 'a: not struct> = Mock<'a>

type Foo =
    abstract member Bar: int

<@ A<Foo>().Create().Bar > 1 @> 

在这种情况下,Bar将始终为0.如果您希望它为非零,则需要进行设置,如下所示:

<@ A<Foo>().Setup(fun f -> <@ f.Bar @>).Returns(2).Create().Bar > 1 @>