这个 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 中修复,并按预期工作。
我相信观察到的编译器行为是有意的,并且完全符合对具有F# Language Spec $10.2.2[<Literal>]定义的属性的值的限制:
右边的表达式必须是一个文字常量表达式,由以下任一组成:
- 一个简单的常量表达式,除了 ()、本机整数文字、无符号本机整数文字、字节数组文字、BigInteger 文字和用户定义的数字文字。—或者—</li>
- 对另一个字面量的引用
考虑
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# 方法,定义枚举文字值的唯一选项将是在let.
差异是由于 C#(MyEnum)0 确实是文字,但 F#enum是 type 的函数int32 -> 'T。
我相信 F# 团队为这个构造添加特殊处理并不难,但不幸的是它还没有。
尽管如此,有一种方法可以完成您的需要,但仅是为了0价值:
type MyEnum =
| None = 0
| Foo = 1
[<Literal>]
let X = MyEnum()