2013-02-27 19 views
7

Próbuję określić ogólny operatora konwersji z ciągu znaków do wyliczenia i chciałbym używać go tak:F # typu ograniczeń na teksty stałe

let day = asEnum<DayOfWeek>("Monday") 

Ale z tej realizacji:

let asEnum<'a, 'b when 'a: (new : unit -> 'a) and 'a : struct and 'a :> ValueType and 'a : enum<'b>> text = 
    match Enum.TryParse<'a>(text) with 
    | true, value -> Some value 
    | false, _ -> None 

mogę użyć tylko to tak:

let day = asEnum<DayOfWeek,_>("Monday") 

lub to:

let day:DayOfWeek option = asEnum("Monday") 

Jeśli pominąć 'a : enum<'b> całkowicie od rodzaju przymusu, mogę mieć to jak chcę, ale jeśli ktoś nie określił to domyślnie int, co bardzo mi się nie podoba, ja wolałby dać błąd czasu kompilacji, tak jak wtedy, gdy określę ograniczenie. Może jest jakaś sztuczka, żeby podać tylko jeden parametr i mieć drugi? Jakieś pomysły?

Odpowiedz

2

Niestety, aby wspomagając w ten sposób ograniczenie wydaje się, trzeba przeliterować to wszystko: (jak KVB wskazał, można uniknąć powielania tych ograniczeń TryParse dodając 'T : enum<int> ograniczenia poza nawiasach kątowych)

działa to również:

let asEnum<'T 
    when 'T : enum<int> 
    and 'T : struct 
    and 'T :> ValueType 
    and 'T : (new : unit -> 'T)> text = 
    match Enum.TryParse<'T>(text) with 
    | true, value -> Some value 
    | _ -> None 

to daje błąd kompilacji, jeśli typ bazowy nie jest int:

type ByteEnum = 
    | None = 0uy 

asEnum<ByteEnum> "None" //ERROR: The type 'int' does not match the type 'byte' 
3

Co powiesz na to?

let asEnum s :'a option when 'a:enum<'b> = 
    match System.Enum.TryParse s with 
    | true, v -> Some v 
    | _ -> None 

// works, but warns that type params shouldn't be given explicitly 
asEnum<System.Reflection.BindingFlags,_> "DeclaredOnly"  
// also okay 
(asEnum "DeclaredOnly" : System.Reflection.BindingFlags option) 
+0

Holy cow. Nawet nie wiedziałem, że to była poprawna składnia. Myślę, że jeśli zmienisz go na '' a: enum ', który da mu to, czego chce. Mógł także zrobić opcję let: System.Reflection.BindingFlags = asEnum "DeclaredOnly" ', aby uniknąć ostrzeżenia. – Daniel

+0

Dlaczego to działa, ale wprowadzanie tego samego ograniczenia między '<' '>' nie powoduje? – Daniel

+0

@Daniel - Nie sądzę, że @ovastus chce, aby 'int' był wymuszony, chce, żeby to było wywnioskowane, jeśli to możliwe (co to jest). – kvb

0

Inną rzeczą próbowałem było to:

type AsEnum = 

    static member Get<'a, 'b when 'a: (new : unit -> 'a) and 'a : struct and 'a :> ValueType and 'a : enum<int>> (text:string) = 

     match Enum.TryParse<'a>(text) with 
     | true, value -> Some value 
     | _ -> None 

    static member Get<'a, 'b when 'a: (new : unit -> 'a) and 'a : struct and 'a :> ValueType and 'a : enum<int64>> (text:string) = 

     match Enum.TryParse<'a>(text) with 
     | true, value -> Some value 
     | _ -> None 

let a = AsEnum.Get<BindingFlags>.Get "DeclaredOnly" 

spróbować, aby zobaczyć, czy mogę dostać kompilator wywnioskować który przeciążać zadzwonić, ale jeśli nie powiedzie się z powodu błędu niejednoznaczności

0

A niewielka aktualizacja około 3 lat później^_^

Korzystanie z tego ciągu znaków do przekształcenia ciągu znaków w wyliczenie

type System.String with 
     /// Strongly-typed shortcut for Enum.TryParse(). 
     member this.ToEnum<'a when 'a :> System.Enum and 'a : struct and 'a : (new: unit -> 'a)>() = 
      let ok, v = System.Enum.TryParse<'a>(this, true) 
      if ok then Some v else None  

Należy zachować ostrożność przy deklaracji wyliczeniowej.

type failingEnum = 
      | FirstValue 
      | SecondValue 
      | AnotherValue 

type compliantEnum = 
      | FirstValue = 0 
      | SecondValue = 1 
      | AnotherValue = 2 

Następnie

let x = "whatever".ToEnum<failingEnum>(); 
//- will give error failingEnum is not compatible with the type System.Enum 

let x = "whatever".ToEnum<compliantEnum>(); 
//- will succeed ! 
+1

Technicznie,' failingEnum' jest typem związku, a nie wyliczeniem. Właśnie dlatego się nie udaje. – CaringDev

+0

Pewnie ... Dzięki za komentarz. Dlatego dodałem do tego komentarz, ponieważ często definiuje się wyliczenie jako związek. Byłem częścią tych nie tak dawno temu :) –

Powiązane problemy