2014-05-05 32 views
13

Uwaga: to pytanie to , a nie to samo, co pytanie: this.Składnia inicjalizacji obiektu C# w języku F #

Niedawno natknąłem jakiś C# składni ja wcześniej nie spotkałem:

Czy istnieje jakiś sposób, aby to zrobić w 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" }}; 

(zauważ inicjalizacji TwoProperty w inicjalizatorze gdy seter jest prywatny - to jest ustawienie właściwości na obiekt przechowywany w TwoProperty, ale NIE przechowywania nową instancję Two w nieruchomości)

Edit: niedawno natknąłem niektórych kodu C# w konstruktorze w MonoTouch tak:

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

najlepszą F # translati na mogłem wymyślić było coś takiego:

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 

To nie jest straszny, ale ma więcej hałasu z wielokrotnym layer referencyjnej powiększonej o jego bardziej konieczne i mniej deklaratywne.

+0

Pokaż nam, co wypróbowałeś do tej pory. Co było dla ciebie trudne? –

+0

@EricLippert Zaktualizowano – mydogisbox

+0

Czy jest to udokumentowana funkcja C#? Umożliwienie wywołania prywatnego setera w tym kontekście wydaje się być błędem. – Daniel

Odpowiedz

3

Czy ma sens obudowanie konstrukcji w oddzielną funkcję inicjującą?

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

Następnie użyj że w kodzie:

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 
+0

Podoba mi się ten pomysł. Myślę, że jeśli zamierzałem zrobić dużo rozwoju w tym środowisku, prawdopodobnie utworzyłbym funkcję pomocniczą z wszystkimi dostępnymi właściwościami jako parametrami opcjonalnymi, aby parametry mogły być nazwane. – mydogisbox

5

Nie sądzę, że F # pozwala na ustawienie właściwości zagnieżdżonych podczas inicjalizacji. Obejściem, zakładając, że jesteś autorem API, jest przekazanie całego obiektu do konstruktora. Eliminuje to potrzebę stosowania programu pobierającego i ustawiającego z różnymi dostępami i sprawia, że ​​generalnie jest dużo czystszy kod F #.

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

type One(twoProperty) = 
    member val TwoProperty = twoProperty 

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

Jak wspomniano w your comment, można utworzyć funkcję pomocnika akceptującą różne właściwości jako opcjonalne parametry. Rozszerzenie typu dobrze by się do tego przydało:

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) 
+0

Niestety, klasa, którą konstruuję, jest UILabel, która jest klasą frakcji Cocoa Touch. – mydogisbox

1

F # 4,0 wyszedł z funkcji, które mogą być przydatne do enkapsulacji odpowiedź @ cokołu. Umożliwia tworzenie właściwości rozszerzenia, które można zainicjować w konstruktorze.