Are .NET enum types actually mutable value types?
回想一下枚举类型的字段,我惊讶地注意到,持有枚举特定实例的实际值的"backing"实例字段不是我想象中的
许多人认为.NET类型系统中的"可变"值类型是"邪恶的",那么为什么枚举类型(例如从C代码创建的)就是这样?
现在,事实证明,C编译器具有某种魔力,可以否认公共实例字段的存在(但请参见下文),但在PowerShell中,您可以这样做:
1 2 3 4 5 6 | prompt> $d = [DayOfWeek]::Thursday prompt> $d Thursday prompt> $d.value__ = 6 prompt> $d Saturday |
字段
现在,为了在C中实现这一点,我不得不使用
下面是C代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // create a single box for all of this example Enum box = DayOfWeek.Thursday; // add box to a hash set var hs = new HashSet<Enum> { box, }; // make a dynamic reference to the same box dynamic boxDyn = box; // see and modify the public instance field Console.WriteLine(boxDyn.value__); // 4 boxDyn.value__ = 6; Console.WriteLine(boxDyn.value__); // 6 now // write out box Console.WriteLine(box); // Saturday, not Thursday // see if box can be found inside our hash set Console.WriteLine(hs.Contains(box)); // False // we know box is in there Console.WriteLine(object.ReferenceEquals(hs.Single(), box)); // True |
我认为这些评论本身就说明了问题。我们可以通过
为什么.NET的设计者选择将枚举类型的实例字段设置为
让我试着为那些不熟悉如何在幕后生成枚举的读者理解这个令人困惑的问题。C代码:
1 | enum E { A, B } |
成为IL
1 2 3 4 5 6 | .class private auto ansi sealed E extends [mscorlib]System.Enum { .field public specialname rtspecialname int32 value__ .field public static literal valuetype E A = int32(0x00000000) .field public static literal valuetype E B = int32(0x00000001) } |
或者,为了在C中重写它,枚举等价于以下伪C:
1 2 3 4 5 6 | struct E : System.Enum { public int value__; public const E A = 0; public const E B = 1; } |
问题是:为什么魔域
我不想做这个设计决定,所以我只能做一个有根据的猜测。我有根据的猜测是:如果字段不是公共的,如何初始化结构的实例?
你做了一个构造器,然后你必须调用它,这就给了你一个抖动的工作,这项工作的性能代价是什么?如果答案是"它给我买了运行时,阻止我自己做一些愚蠢和危险的事情,我不应该在第一时间做,必须真正努力去做",那么我向你提交,这不是一个令人信服的成本效益比。
Since the instance was in a hashtable and the mutation lead to a change of hash code, the instance is in the wrong"bucket" after the mutation, and the HashSet cannot function.
这是几英里过去的"如果它伤害,当你这样做,然后停止这样做"行。