Open
Description
Hello,
After hours struggling to retrieve the values of some custom attributes assigned to an F# method return type annotation, I have found an unexpected behavior and would like to know why it did not worked as I thought.
Suppose that you have an F# method which returns a tuple value:
type HelloTupleWithoutParentheses =
static member Format name : string * string =
("Hello " + name + "!", "Goodbye " + name + "!")
Then, you code a custom attribute containing a string describing each tuple field:
[<AttributeUsage(AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)>]
type ReturnParameterDescriptionAttribute(info:string) =
inherit Attribute()
member x.Info = info
If you apply it to the Format
method:
type HelloTupleWithoutParentheses =
static member Format name :
[<ReturnParameterDescription("A string containing 'Hello <name>!'.")>]
[<ReturnParameterDescription("A string containing 'Goodbye <name>!'.")>]
string * string =
("Hello " + name + "!", "Goodbye " + name + "!")
The following reflection will not return anything:
let methodInfo = typeof<HelloTupleWithoutParentheses>.GetMethod("Format")
methodInfo.ReturnParameter.GetCustomAttributes(typeof<ReturnParameterDescriptionAttribute>, false)
Whereas it works correctly when the tuple type annotation is surrounded by parentheses:
type HelloTupleWithParentheses =
static member Format name :
[<ReturnParameterDescription("A string containing 'Hello <name>!'.")>]
[<ReturnParameterDescription("A string containing 'Goodbye <name>!'.")>]
(string * string) =
("Hello " + name + "!", "Goodbye " + name + "!")
Does anyone knows why the first attempt does not returns the custom attributes?
Am I missing something? Is it a parser bug?
Full example of my problem (try it in your web browser):
open System
[<AttributeUsage(AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)>]
type ReturnParameterDescriptionAttribute(info:string) =
inherit Attribute()
member x.Info = info
type HelloSimple =
static member Format name :
[<ReturnParameterDescription("A string containing 'Hello <name>!'.")>]
string =
"Hello " + name + "!"
type HelloTupleWithParentheses =
static member Format name :
[<ReturnParameterDescription("A string containing 'Hello <name>!'.")>]
[<ReturnParameterDescription("A string containing 'Goodbye <name>!'.")>]
(string * string) =
("Hello " + name + "!", "Goodbye " + name + "!")
type HelloTupleWithoutParentheses =
static member Format name :
[<ReturnParameterDescription("A string containing 'Hello <name>!'.")>]
[<ReturnParameterDescription("A string containing 'Goodbye <name>!'.")>]
string * string =
("Hello " + name + "!", "Goodbye " + name + "!")
// Print the descriptions for each implementation.
[| typeof<HelloSimple>; typeof<HelloTupleWithParentheses>; typeof<HelloTupleWithoutParentheses> |]
|> Array.map (fun t ->
printfn "--- %s ---" t.Name
t.GetMethod("Format").ReturnParameter.GetCustomAttributes(typeof<ReturnParameterDescriptionAttribute>, false)
|> Array.map (fun attr -> (attr :?> ReturnParameterDescriptionAttribute).Info |> printfn "%s")
)
Metadata
Metadata
Assignees
Labels
Type
Projects
Status