3

在 C# 中,可以用相当简洁的语法构造对象树:

var button = new Button() { Content = "Foo" };

在 F# 中是否有一种惯用的方式来做类似的事情?

记录有很好的语法:

let button = { Content = "Foo" }

据我所知,对象构造似乎是另一回事。通常我会编写如下代码:

let button = new Button()
button.Content <- "Foo"

甚至:

let button =
    let x = new Button()
    x.Content <- "Foo"
    x

解决该问题的一种方法是使用自定义流式组合运算符:

// Helper that makes fluent-style possible
let inline (.&) (value : 'T) (init: 'T -> unit) : 'T =
    init value
    value

let button = new Button() .& (fun x -> x.Content <- "Foo")

是否有内置语法来实现这一点 - 或其他推荐的方法?

4

2 回答 2

6

F# 允许您在构造函数调用中设置属性,所以我认为这应该适合您:

let button = Button(Content = "Foo")
于 2021-12-11T22:22:17.200 回答
3

在 C# 中,这种漂亮的语法称为对象初始化器,然后()可以删除 (1)。要在初始化后更改对象“内联” (流利的样式),我喜欢使用With()类似于您的.&运算符(2)的扩展方法:

var button = new Button { Content = "Foo" }; // (1)

// (2)
public static T With<T>(this T @this, Action<T> update)
{
    change(@this);
    return @this;
}

var button2 = button.With(x => x.Content = "Bar")

在 F# 中,对于那些更喜欢管道而不是运算符的人,可以将函数命名为tap(参见RxJs)或tee(由 Scott Wlaschin在这里):

// f: ('a -> 'b) -> x: 'a -> 'a
let inline tee f x =
    f x |> ignore
    x

let button =
    Button(Content = "Foo")
    |> tee (fun x -> x.Color <- Blue)
    |> tee (fun x -> x.Content <- "Bar")
于 2021-12-12T08:42:44.797 回答