F#允许您选择命名联合案例属性。 如果不这样,编译器将在编译期间自动为您选择一个名称(Item1 ... n)。
type Foo =
| Nothing
| AutomaticallyNamed of string
| Named of nameOfProperty: string
我唯一能想到的就是GetFields返回的名称上的简单字符串比较。
let testCase = Named "bar"
let caseInfo, _ = FSharpValue.GetUnionFields(testCase, typeof<Foo>)
caseInfo.GetFields()
是否有更可靠的方法来确定编译器是否生成了名称?
答案 0 :(得分:3)
非常有趣的问题。事实证明,case字段实际上并不存储为System.Tuple
,而是编译成标准.NET属性,在嵌套类上有一个代表工会案例的支持字段。
如果您查看ILSpy或类似反汇编程序中生成的代码,您会发现一些奇怪的部分:
该属性没有任何内容可以告诉您它有一个用户提供的名称,所以如果您在这里寻找一个漂亮而干净的解决方案,那你就不走运了。
但是,当字段具有用户提供的名称时,将使用名称前面的下划线(即_nameOfProperty
)生成支持字段(不是属性)。因此,如果在union case嵌套类上调用GetMembers
,则可以使用反射向下钻取,提供NonPublic ||| Instance
绑定标记。
或者,相同的名称用于union case类的单个非公共构造函数的构造函数参数,因此您可以通过再次检查构造函数的参数来获取相同的信息 - GetConstructors
使用非公共绑定标志,然后GetParameters
。
事情从来都不是这么简单 - 这里有一点需要注意:如果你使用编译器使用的命名方案命名你的字段 - 即Item42
- 它将被编译而没有下划线,就像它由编译器分配。虽然幸运的是编译器很聪明,可以跳过你已经使用的序数。
因此,理论上您可以检测该名称是否是用户提供的,但它很麻烦,并且依赖于内部实施细节,这些细节不能保证保持不变。