Синтаксис инициализации объекта C# В F#
Пожалуйста, обратите внимание: этот вопрос не аналогично этой вопрос.
недавно я столкнулся с синтаксисом 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" }};
(обратите внимание на инициализации TwoProperty
в инициализаторе, когда сеттер является частным-он устанавливает свойство объекта, хранящегося в TwoProperty
, а не сохранение нового экземпляра Two
в собственность)
изменить: Недавно я столкнулся с некоторым кодом C# в конструкторе в monotouch, как это:
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
ссылка плюс его более необходимым и менее декларативной.
3 ответов
имеет ли смысл инкапсулировать конструкцию в отдельную функцию инициализатора?
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
Я не думаю, что F# позволяет устанавливать вложенные свойства во время инициализации. Обходной путь, предполагая, что вы являетесь автором API, должен передать весь объект конструктору. Это исключает потребность для геттера и сеттера с различными accessibilities и делает для гораздо чище кода 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)
F# 4.0 вышел с функцией, которая может быть полезна для инкапсуляции ответа @plinth. Он позволяет создавать свойства расширения, которые могут быть инициализированы в конструкторе.