2013-02-27 201 views
7

我試圖定義一個字符串的通用轉換操作符來枚舉,我想用這樣的:F#類型約束

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

但是這個實現:

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 

我只能用這樣的:

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

或本:

​​

如果我從類型約束省略'a : enum<'b>乾脆,我可以擁有它,因爲我想,但後來如果有人不指定類型,則默認爲int,我真的不喜歡,我'd喜歡它給編譯時錯誤,就像我指定約束時一樣錯誤

也許有任何技巧只指定一個類型參數,並讓另一個類型參數被傳遞?有任何想法嗎?

回答

2

不幸的是,爲了增加它似乎你必須拼了這一切的約束: (如KVB指出,就可以避免通過添加'T : enum<int>約束的角度括號外上覆制TryParse的約束)

這也適用:

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 

這給出了一個編譯時錯誤,如果基礎類型不int

type ByteEnum = 
    | None = 0uy 

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

這個怎麼樣?

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

聖牛。我甚至不知道這是有效的語法。我想如果你把它改成「a:enum 」,那會給他他想要的東西。他也可以使用'let e:System.Reflection.BindingFlags option = asEnum「DeclaredOnly」'來避免警告。 – Daniel 2013-02-27 15:55:33

+0

爲什麼這個工作,但在'<' '>'之間放置相同的約束不? – Daniel 2013-02-27 15:57:46

+0

@丹尼爾 - 我不認爲@ovastus希望'int'被迫,他希望在可能的情況下推斷它(它是)。 – kvb 2013-02-27 16:13:21

0

我想另一件事是這樣的:

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" 

嘗試看看如果我能得到編譯器來推斷其超載打電話,但如果失敗,多義性錯誤

0

一小更新的東西樣3年後^ _^

使用此字符串擴展字符串轉換爲一個枚舉

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  

請注意您的枚舉聲明。

type failingEnum = 
      | FirstValue 
      | SecondValue 
      | AnotherValue 

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

然後

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

從技術上講,'failingEnum'是聯合類型,而不是枚舉。這就是它失敗的原因。 – CaringDev 2016-01-27 12:50:33

+0

當然...感謝您的評論。這就是爲什麼我添加了評論,因爲人們經常將枚舉定義爲union。我是那些不久前的那些人的一部分:) – 2016-01-27 15:36:49