【问题标题】:C# object initialization syntax in F#F# 中的 C# 对象初始化语法
【发布时间】:2014-06-21 05:49:38
【问题描述】:

请注意:此问题不与this问题相同。

我最近遇到了一些我以前没有遇到过的 C# 语法:

有没有办法在 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" }};

(注意当 setter 为私有时,初始化器中 TwoProperty 的初始化 - 它正在为存储在 TwoProperty 中的对象设置属性,但 不 存储 @987654325 的新实例@在属性中)

编辑: 我最近在 monotouch 的构造函数中遇到了一些 C# 代码,如下所示:

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

我能想到的最好的 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  

这并不可怕,但由于重复的 layer 引用加上它的命令性更强且声明性更少,确实会产生更多噪音。

【问题讨论】:

  • 向我们展示您迄今为止的尝试。你觉得有什么困难?
  • 这是 C# 的文档化功能吗?允许在这种情况下调用私有 setter 似乎是一个错误。
  • @Daniel 它没有调用私人二传手。它在设置器中包含的对象上设置属性。请参阅 F# 翻译以了解 C# 正在做什么。
  • 我明白了。抱歉,我看得太快了。我认为这在 F# 中是不可能的。

标签: c# f# c#-to-f# object-initializers


【解决方案1】:

我认为 F# 不允许在初始化期间设置嵌套属性。假设您是 API 的作者,一种解决方法是将整个对象传递给构造函数。这消除了对具有不同可访问性的 getter 和 setter 的需求,并使 F# 代码整体上更加简洁。

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

type One(twoProperty) =
    member val TwoProperty = twoProperty

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

正如您在your comment 中提到的,您可以创建一个辅助函数,接受各种属性作为可选参数。类型扩展可以很好地解决这个问题:

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)

【讨论】:

  • 遗憾的是,我正在构建的类是一个 UILabel,它是一个 Cocoa Touch 框架类。
【解决方案2】:

将构造封装到单独的初始化函数中是否有意义?

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()

然后在你的代码中使用它:

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

【讨论】:

  • 我喜欢这个主意。我想如果我要使用这个框架进行大量开发,我可能会创建一个辅助函数,将所有可用属性作为可选参数,以便为参数命名。
【解决方案3】:

F# 4.0 推出了一个可能对封装@plinth 的答案有用的功能。它允许创建可以在构造函数中初始化的扩展属性。

【讨论】:

    猜你喜欢
    • 2016-02-26
    • 2010-09-27
    • 1970-01-01
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多