2013-02-27 18 views
7

Ich versuche, einen allgemeinen Umwandlungsoperator aus einer Zeichenfolge zu einem Enum zu definieren, und ich mag es so verwenden:F # Typ Einschränkungen für Aufzählungen

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

Aber mit dieser Umsetzung:

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 

ich kann es nur wie folgt verwenden:

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

oder dies:

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

Wenn ich die 'a : enum<'b> ganz aus der Art Zwang weglassen, ich kann es haben, wie ich will, aber dann, wenn jemand nicht den Typ spezifiziert wird es int Standard, was ich nicht mag, ich würde es vorziehen, einen Kompilierzeitfehler zu geben, wie es tut, wenn ich eine Beschränkung spezifiziere

Vielleicht gibt es irgendeinen Trick, um nur einen Typparameter zu spezifizieren und hat das andere eingegebene? Irgendwelche Ideen?

Antwort

2

Leider, um die Einschränkung zu erweitern es Sie alle heraus buchstabieren müssen es scheint: (wie kvb darauf hingewiesen, können Sie vermeiden, die 'T : enum<int> Einschränkung außerhalb der spitzen Klammern die Einschränkungen für TryParse Duplizieren durch Zugabe)

Dies funktioniert auch:

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 

Dieser einen Fehler Compile-Zeit gibt, wenn der zugrunde liegenden Typ nicht int ist:

type ByteEnum = 
    | None = 0uy 

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

Wie wäre es damit?

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

Heilige Kuh. Ich wusste nicht einmal, dass das eine gültige Syntax war. Ich denke, wenn Sie es in 'a ändern: enum ' das wird ihm geben, was er will. Er könnte auch 'let e: System.Reflection.BindingFlags option = asEnum" DeclaredOnly "' machen, um die Warnung zu vermeiden. – Daniel

+0

Warum funktioniert das, obwohl die gleiche Bedingung zwischen "<' '>" nicht gestellt wird? – Daniel

+0

@Daniel - Ich glaube nicht, dass @ovastus will, dass "int" gezwungen wird, er möchte, dass es gefolgert wird, wenn möglich (was es ist). – kvb

0

Eine andere Sache, die ich versuchte, war dies:

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" 

, um zu versuchen, um zu sehen, ob ich den Compiler bekommen konnte geschlossen werden, welche zu nennen überlasten, aber wenn nicht mit einer Mehrdeutigkeit Fehler

0

A wenig update so etwas wie 3 Jahre danach^_^

Mit dieser String-Extension wird eine Zeichenfolge in ein Enum umgewandelt

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  

Seien Sie vorsichtig mit Ihrer Enum-Deklaration.

type failingEnum = 
      | FirstValue 
      | SecondValue 
      | AnotherValue 

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

Dann

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

Technisch gesehen ist' failingEnum' ein Union-Typ und keine Enumeration. Deshalb schlägt es fehl. – CaringDev

+0

Sicher ... Danke für Ihren Kommentar. Deshalb habe ich den Kommentar hinzugefügt, weil man Enum oft als Vereinigung definiert. Ich war Teil von denen nicht so lange her :) –