Подтвердить что ты не робот

Синтаксис инициализации объекта С# в 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" }};

(обратите внимание на инициализацию TwoProperty в инициализаторе, когда сеттер является закрытым - он устанавливает свойство объекта, хранящегося в TwoProperty, но НЕ сохраняя новый экземпляр Two в свойстве)

Изменить: Недавно я встретил некоторый код С# в конструкторе в монототе:

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, а также более насущной и менее декларативной.

4b9b3361

Ответ 1

Имеет ли смысл инкапсулировать конструкцию в отдельную функцию инициализации?

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

Ответ 2

Я не думаю, что F # позволяет устанавливать вложенные свойства во время инициализации. Обходной путь, предполагающий, что вы являетесь автором API, заключается в передаче всего объекта конструктору. Это устраняет необходимость в геттере и сеттере с различными доступными возможностями и обеспечивает гораздо более чистый код F # в целом.

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

type One(twoProperty) =
    member val TwoProperty = twoProperty

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

Как вы упомянули в ваш комментарий, вы можете создать вспомогательную функцию, принимающую различные свойства в качестве необязательных параметров. Расширение типа будет хорошо работать для этого:

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)

Ответ 3

F # 4.0 вышел с функцией, которая может быть полезна для инкапсуляции ответа @plinth. Он позволяет создавать свойства расширения, которые могут быть инициализированы в конструкторе.