2009-08-11 19 views
16

Chcę uzyskać równowartość Enum.GetName dla członka dyskryminacji F #. Wywołanie ToString() daje mi TypeName + MemberName, co nie jest dokładnie tym, czego chcę. Mógłbym go podciąć, oczywiście, ale czy to jest bezpieczne? A może jest lepszy sposób?Co to jest odpowiednik Enum.GetName dla członka związku F #?

+1

Uwaga! To samo wyrażenie, x.ToString(), przy różnych uruchomieniach programu czasami da mi AssemblyName + TypeName, a czasami AssemblyName + TypeName + MemberName. Kolejne identyczne wyrażenie tego samego typu w innym miejscu zawsze da mi AssemblyName + TypeName + MemberName. Ten sam problem z x.GetType(). Nazwa. Przyjęta odpowiedź jest dobra. –

Odpowiedz

26

trzeba użyć klas w Microsoft.FSharp.Reflection nazw tak: (? I szybko z powodu braku refleksji dla jednej z metod)

open Microsoft.FSharp.Reflection 

///Returns the case name of the object with union type 'ty. 
let GetUnionCaseName (x:'a) = 
    match FSharpValue.GetUnionFields(x, typeof<'a>) with 
    | case, _ -> case.Name 

///Returns the case names of union type 'ty. 
let GetUnionCaseNames <'ty>() = 
    FSharpType.GetUnionCases(typeof<'ty>) |> Array.map (fun info -> info.Name) 

// Example 
type Beverage = 
    | Coffee 
    | Tea 

let t = Tea 
> val t : Beverage = Tea 

GetUnionCaseName(t) 
> val it : string = "Tea" 

GetUnionCaseNames<Beverage>() 
> val it : string array = [|"Coffee"; "Tea"|] 
+1

Przyszedłem tutaj ze składnią "' GetUnionFields''' - dzięki za to. Gdy jestem tutaj, pomyślałem, że zwrócę uwagę, że '' 'GetUnionCaseName''' może być napisany nieco bardziej zwięźle jako: ' '' let GetUnionCaseName (e: 'a) = (FSharpValue.GetUnionFields (e, typeof <'a>) |> fst) .Nazwa '' ' – philsquared

+0

Zauważ, że jest to bardzo powolne podejście, Na pewno chcesz buforować wyniki, aby uzyskać trochę wydajności z tego –

2

@ prac odpowiedziami DanielAsher, ale aby uczynić go bardziej elegancki Chciałbym zrobić to w następujący sposób: (. Zainspirowany this i this)

type Beverage = 
    | Coffee 
    | Tea 
    static member ToStrings() = 
     Microsoft.FSharp.Reflection.FSharpType.GetUnionCases(typeof<Beverage>) 
      |> Array.map (fun info -> info.Name) 
    override self.ToString() = 
     sprintf "%A" self 

0

chciałbym zaproponować coś jeszcze bardziej zwięzły:

open Microsoft.FSharp.Reflection 

type Coffee = { Country: string; Intensity: int } 

type Beverage = 
    | Tea 
    | Coffee of Coffee 

    member x.GetName() = 
     match FSharpValue.GetUnionFields(x, x.GetType()) with 
     | (case, _) -> case.Name 

Kiedy sprawa unii jest prosta, GetName() może przynieść takie same jak ToString():

> let tea = Tea 
val tea : Beverage = Tea 

> tea.GetName() 
val it : string = "Tea" 

> tea.ToString() 
val it : string = "Tea" 

Jednakże, jeśli sprawa unii jest hodowca, nie będzie różnica:.

> let coffee = Coffee ({ Country = "Kenya"; Intensity = 42 }) 
val coffee : Beverage = Coffee {Country = "Kenya"; Intensity = 42;} 

> coffee.GetName() 
val it : string = "Coffee" 

> coffee.ToString() 
val it : string = "Coffee {Country = "Kenya";  Intensity = 42;}" 
Powiązane problemy