Last active
September 14, 2020 17:27
-
-
Save allykzam/7135f89daf6e6bd2a105 to your computer and use it in GitHub Desktop.
F# code for getting attribute data off discriminated union cases
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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