如何在枚举中保留值类型

9

让我们看下面的代码片段,并假设既不能更改 MyAttribute 也不能更改 test 函数。

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)

我希望 test 返回 B,但它返回了2。生成的IL代码显示枚举类型的信息丢失了,传递给属性的值只是2。

是否有任何方法(我猜应该是一些属性)来保留属性值中的类型?更有趣的是,等效的C#代码按预期工作。

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)

1
你能分享一下你提到的等价的C#代码吗? - MarcinJuraszek
@MarcinJuraszek:已编辑 - Novakov
你在 F# 中使用 false,在 C# 中使用 true 调用了 GetCustomAttributes() 方法;不确定这样做的作用是什么,但至少有所区别。 - TeaDrivenDev
1
看起来C#和F#编译枚举(或属性?)的方式有所不同。如果你在C#中定义了所有类型,然后在F#的test函数中使用它们,它也会返回枚举案例名称而不是整数值。 - TeaDrivenDev
1
我创建了一个问题:https://github.com/Microsoft/visualfsharp/issues/995 - Novakov
显示剩余2条评论
1个回答

1
我猜测,对于编译器内部的了解非常有限,但我认为这与类型推断有关。int和Enum之间存在等价性,我怀疑类型推断将其缩减到最低可能的类型,即int。您可以通过执行以下操作来修复此问题。
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)

问题在于我无法更改负责读取该属性的代码 - 它位于另一个库中,该库对我的枚举没有任何了解。 - Novakov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接