简体   繁体   English

F#中的C#对象初始化语法

[英]C# object initialization syntax in F#

Please note: this question is not the same as this question. 请注意:这个问题和这个问题一样。

I recently came across some C# syntax I hadn't previously encountered: 我最近遇到了一些我以前没有遇到过的C#语法:

Is there any way to do this in F#? 在F#中有没有办法做到这一点?

class Two
{
    public string Test { get; set; }
}

class One
{
    public One()
    {
        TwoProperty = new Two();
    }
    public Two TwoProperty { get; private set; }
}

var test = new One(){ TwoProperty = { Test = "Test String" }};

(note the initialization of TwoProperty in the initializer when the setter is private - it is setting a property on the object stored in TwoProperty , but NOT storing a new instance of Two in the property) (注意的初始化TwoProperty在初始化时的setter是私有的-它是设置存储在对象上的属性TwoProperty ,而不是存储的新实例Two的属性)

Edit: I recently came across some C# code in a constructor in monotouch like this: 编辑:我最近在monotouch的构造函数中遇到了一些C#代码,如下所示:

nameLabel = new UILabel {
    TextColor = UIColor.White,
    Layer = {
        ShadowRadius = 3,
        ShadowColor = UIColor.Black.CGColor,
        ShadowOffset = new System.Drawing.SizeF(0,1f),
        ShadowOpacity = .5f
    }
};

The best F# translation I could come up with was something like this: 我能想出的最好的F#翻译是这样的:

let nameLabel = new UILabel ( TextColor = UIColor.White )
do let layer = nameLabel.Layer
   layer.ShadowRadius <- 3.0f
   layer.ShadowColor <- UIColor.Black.CGColor
   layer.ShadowOffset <- new System.Drawing.SizeF(0.0f,1.0f)
   layer.ShadowOpacity <- 0.5f  

This isn't terrible, but it does have more noise with the repeated layer reference plus its more imperative and less declarative. 这并不可怕,但它确实有更多的噪音与重复的layer参考加上更多的命令和更少的声明。

I don't think F# allows setting nested properties during initialization. 我不认为F#允许在初始化期间设置嵌套属性。 A workaround, assuming you're the author of the API, is to pass the entire object to the constructor. 假设您是API的作者,解决方法是将整个对象传递给构造函数。 This eliminates the need for getter and setter with different accessibilities and makes for much cleaner F# code overall. 这消除了对具有不同可访问性的getter和setter的需求,并使整个F#代码更加清晰。

type Two() =
    member val Test = "" with get, set

type One(twoProperty) =
    member val TwoProperty = twoProperty

let test = One(Two(Test="foo"))

As you mentioned in your comment , you could create a helper function accepting various properties as optional parameters. 正如您在评论中提到的,您可以创建一个辅助函数,接受各种属性作为可选参数。 A type extension would work well for this: 类型扩展适用于此:

type UILayer with
    member this.Configure(?shadowRadius, ?shadowColor, ?shadowOffset, ?shadowOpacity) = 
        this.ShadowRadius <- defaultArg shadowRadius this.ShadowRadius
        this.ShadowColor <- defaultArg shadowColor this.ShadowColor
        this.ShadowOffset <- defaultArg shadowOffset this.ShadowOffset
        this.ShadowOpacity <- defaultArg shadowOpacity this.ShadowOpacity

let nameLabel = UILabel(TextColor=UIColor.White)
nameLabel.Layer.Configure(
    shadowRadius=3.0f, 
    shadowColor=UIColor.Black.CGColor, 
    shadowOffset=SizeF(0.0f, 1.0f), 
    shadowOpacity=0.5f)

Would it make sense to encapsulate the construction into a separate initializer function? 将构造封装到单独的初始化函数中是否有意义?

let layerInit layer radius color offset opacity =
    do
       layer.ShadowRadius <- radius
       layer.ShadowColor <- color
       layer.ShadowOffset <- offset
       layer.ShadowOpacity <- opacity
    layer // I do this in case you want to use this fluently or pass in new Layer()

Then use that in your code: 然后在您的代码中使用它:

let nameLabel = new UILabel ( TextColor = UIColor.White )
layerInit nameLabel.Layer 3.0f UIColor.Black.CGColor new System.Drawing.SizeF(0.0f,1.0f) 0.5f |> ignore

F# 4.0 came out with a feature which might be useful to encapsulate @plinth's answer. F#4.0推出了一个功能,可能有助于封装@plinth的答案。 It allows the creation of extension properties, which can be initialized in the constructor. 它允许创建扩展属性,可以在构造函数中初始化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM