Let's look at the following piece of code and assume that both MyAttribute
and test
function cannot be changed.
type MyAttribute() =
inherit Attribute()
let mutable prop = null
member this.Prop
with get(): obj = prop
and set(value) = prop <- value
type MyEnum =
| A = 1
| B = 2
[<My(Prop = MyEnum.B)>]
type MyClass = class
end
let test () =
let t = typeof<MyClass>
let a = t.GetCustomAttributes(false).[0] :?> MyAttribute
let e = a.Prop
Convert.ToString(e, Globalization.CultureInfo.CurrentCulture)
I would expect that test
return B
but it returns 2. Generated IL code shows that information about enum type is lost and value passed to attribute is just 2.
Is there any way (I guess it should be some attribute) to preserve type in attribute value? Whats more interesting equivalent code in C# works as expected
Equivalent C#:
class MyAttribute : Attribute
{
public object A { get; set; }
}
enum T { A,B,C }
[My(A = T.A)]
class MyClass
{ }
var a = typeof(MyClass).GetCustomAttributes(false)[0] as MyAttribute;
Convert.ToString(a.A, System.Globalization.CultureInfo.CurrentCulture)
I'm guessing and my knowledge on the internals of the compiler are actually quiet limited but I guess this is something to do with type inference. There is an equivalency between int <-> Enum, and I suspect that the type inference is reducing this to the lowest possible type, in this case int. You can fix this by doing the following
open System
type MyAttribute() =
inherit Attribute()
let mutable prop = null
member this.Prop
with get(): obj = prop
and set(value) = prop <- value
type MyEnum =
| A = 1
| B = 2
[<My(Prop = MyEnum.B)>]
type MyClass = class
end
let test () =
let t = typeof<MyClass>
let a = t.GetCustomAttributes(false).[0] :?> MyAttribute
let e = a.Prop :?> MyEnum //Note
Convert.ToString(e, Globalization.CultureInfo.CurrentCulture)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With