I want to convert a string representations of few dozen enum types to enum values. It's easy to convert string to concrete type:
Enum.Parse(typeof<FontStyle>,"Bold") |> unbox<FontStyle>
but for now i want to write function where type and string are parameters. The best one i can write is:
> let s2e (_: 'a) s = Enum.Parse(typeof<'a>,s) |> unbox<'a>;;
val s2e : 'a -> string -> 'a
> s2e FontStyle.Regular "Bold";;
val it开发者_JS百科 : FontStyle = Bold
Is there any option to write something like this but with type itself as first argument?
The function needs to take a single type parameter, which will be the type of the returned enum. However, you don't need to specify the type using a "fake" parameter that isn't used anywhere in the code - you can specify the actual type parameter when calling the function using the same notation as for example when calling defaultof<SomeType>
.
The following modified function takes a single type parameter which occurs only in the return type (to avoid confusing SO code formatter, I replaced ' with ´ in the code):
> let parseEnum<´a> s = Enum.Parse(typeof<´a>,s) |> unbox<´a>;;
val parseEnum : string -> ´a
When calling the function, you need to specify the type explicitly:
> parseEnum<FontStyle> "Bold";;
val it : FontStyle = Bold
Your solution was pretty close to this - the only change is that you can specify the type parameter explicitly instead of providing a witness value to guide the type inference.
Tomas's answer is good. Additionally, note that you can apply F#'s enum
constraints to prevent nonsensical type parameters from being used:
let parseEnum<'t,'u when 't:enum<'u>> s = System.Enum.Parse(typeof<'t>, s) :?> 't
(parseEnum "Class" : System.AttributeTargets)
Now calling (parseEnum "Test" : int)
will fail at compile time since int
is not an enum.
EDIT
Since we don't actually do anything with the underlying type 'u
, we don't need the full power of F#'s enum constraints, as ssp points out in a comment. This is easier to use because it only has a single type parameter:
let parseEnum<'t when 't :> System.Enum and 't : struct> s =
System.Enum.Parse(typeof<'t>, s) :?> 't
Note that the struct
constraint prevents using System.Enum
itself as the type argument.
精彩评论