如何使用基础值定义枚举常量

时间:2013-01-25 22:12:45

标签: f# enums constants

这个C#的F#等价物是什么:

const MyEnum None = (MyEnum)1;

这不起作用:

[<Literal>]
let None : MyEnum = enum 1 //ERROR: not a valid constant expression

虽然奇怪的是,它在属性构造函数中没问题:

[<MyAttribute(enum 1)>]
type T = class end

这种差异似乎很奇怪。

更新

这已在v3.1中修复,并按预期工作。

2 个答案:

答案 0 :(得分:2)

我认为观察到的编译器行为是有意的,完全符合F# Language Spec $10.2.2:

定义[<Literal>]属性的值的限制
  

右侧表达式必须是 literal 常量表达式,它由以下两者组成:

     
      
  • 一个简单的常量表达式,除了(),本机整数文字,无符号本机整数   文字,字节数组文字,BigInteger文字和用户定义的数字文字。   -OR -
  •   
  • 对另一个文字的引用
  •   

考虑

type MyEnum =
| Case1 = 1
| Case2 = 2

然后

[<Literal>]
let Valid: MyEnum = MyEnum.Case1 // Literal enumeration case on the right

很乐意编译,但

[<Literal>]
let Invalid: MyEnum = enum<MyEnum>(1) // Expression on the right
                                      // generating constant value, which
                                      // potentially might be completely off
                                      // legit MyEnum cases

不会,虽然在[<Literal>]上下文之外,两个语句都会编译成完全相同的IL。

假设[<Literal>]属性是使C#const等价的唯一F#方式,定义枚举文字值的唯一选择是在{{的右侧使用正确类型的文字枚举情况。 1}}。

答案 1 :(得分:1)

差异是由于C#(MyEnum)0 确实是文字,但F#enumint32 -> 'T类型的函数。
我相信F#团队为这个构造添加特殊处理并不困难,但不幸的是它还没有。

尽管如此,有一种方法可以满足您的需求,但仅适用于0值:

type MyEnum =
    | None = 0
    | Foo = 1

[<Literal>]
let X = MyEnum()