2013-02-27 19 views
7

sto cercando di definire un operatore di conversione generica da una stringa in un Enum, e mi piacerebbe utilizzarlo in questo modo:F # tipo vincoli sulle enumerazioni

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

Ma con questa implementazione:

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 

posso usare solo in questo modo:

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

o questo:

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

Se Tralascio il 'a : enum<'b> del tutto dal vincolo di tipo, posso avere come voglio, ma poi se qualcuno non specifica il tipo di questo verrà impostato a int, che davvero non mi piace, mi preferisco dare un errore di compilazione come fa quando specificano un vincolo

Forse c'è qualche trucco per specificare solo un parametro di tipo e l'altro ha dedotto? Qualche idea?

risposta

2

Purtroppo, al fine di aumentare il vincolo sembra avere a precisare tutto fuori: (come KVB ha sottolineato, è possibile evitare di duplicare i vincoli TryParse con l'aggiunta del vincolo 'T : enum<int> fuori le parentesi angolari)

Questo funziona anche:

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 

Questo dà un errore di compilazione se il tipo di fondo non è int:

type ByteEnum = 
    | None = 0uy 

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

Che ne dici di questo?

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

Porca vacca. Non sapevo nemmeno che fosse una sintassi valida. Penso che se lo cambi in ''a: enum ' questo gli darà quello che vuole. Potrebbe anche fare 'let e: System.Reflection.BindingFlags option = asEnum" DeclaredOnly "' per evitare l'avviso. – Daniel

+0

Perché funziona, eppure non applica lo stesso vincolo tra "<' '>"? – Daniel

+0

@Daniel - Non penso che @ovastus voglia che 'int' sia forzato, vuole che sia dedotto se possibile (che è). – kvb

0

Un'altra cosa che ho provato è stato questo:

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" 

per cercare di vedere se ho potuto ottenere il compilatore di dedurre che sovraccarico di chiamare, ma se fallisce con un errore di ambiguità

0

A piccolo aggiornamento qualcosa come 3 anni dopo^_^

Utilizzando questa estensione di stringa per convertire stringa in un enum

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  

Prestare attenzione alla dichiarazione enum.

type failingEnum = 
      | FirstValue 
      | SecondValue 
      | AnotherValue 

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

Poi

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

Tecnicamente,' failingEnum' è un tipo di unione e non un enum. Ecco perché fallisce. – CaringDev

+0

Certo ... Grazie per il tuo commento. Ecco perché ho aggiunto il commento, perché spesso definisco enum come unione. Facevo parte di quelli non molto tempo fa :) –

Problemi correlati