F# code for getting attribute data off discriminated union cases
type FatalError(message: string) = | |
inherit System.Attribute() | |
member __.Message = message | |
type Errors = | |
| [<FatalError("The value specified is currently not available")>] UnknownValue | |
| NotAnError | |
let PrintErrorMessage : Errors -> string = | |
fun err -> | |
// Get UnionCaseInfo value from the F# reflection tools | |
let (case, _args) = Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields(err, typeof<Errors>) | |
// Pull all attributes | |
let attributes = case.GetCustomAttributes() | |
// Find the attributes that have an error message | |
let haveError = | |
attributes | |
|> Seq.ofArray | |
// Filter for the FatalError values | |
|> Seq.filter (fun x -> x :? FatalError) | |
// Cast each value | |
|> Seq.map (fun x -> x :?> FatalError) | |
// Seq.take breaks if there aren't enough, so use Seq.truncate instead | |
|> Seq.truncate 1 | |
|> List.ofSeq | |
// If the FatalError attribute wasn't found, give a default message | |
if haveError.IsEmpty then "(no error message available)" | |
else haveError.Head.Message | |
printfn "%s" <| PrintErrorMessage Errors.UnknownValue | |
printfn "%s" <| PrintErrorMessage Errors.NotAnError | |
// Alternative version of PrintErrorMessage which returns the attribute | |
// Allows providing a default or "backup" value | |
let GetAttribute<'T> : 'T -> obj -> 'T = | |
fun backup value -> | |
let (case, _args) = Microsoft.FSharp.Reflection.FSharpValue.GetUnionFields(value, value.GetType()) | |
let attributeValue = | |
case.GetCustomAttributes() | |
|> Seq.ofArray | |
|> Seq.filter (fun x -> x :? 'T) | |
|> Seq.truncate 1 | |
|> Seq.map (fun x -> x :?> 'T) | |
|> List.ofSeq | |
if attributeValue.IsEmpty then backup | |
else attributeValue.Head | |
let GetFatalErrorMessage = GetAttribute <| FatalError("(no error message available)") | |
let unknownValue = GetFatalErrorMessage Errors.UnknownValue |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment