通过反思,在枚举类型的字段中,我惊讶地注意到保存枚举的特定实例的实际值的“支持”实例字段不是private
,正如我所想的那样,而是public
。它也不readonly
是。(IsPublic
对,IsInitOnly
错。)
许多人认为 .NET 类型系统中的“可变”值类型是“邪恶的”,那么为什么枚举类型(例如从 C# 代码创建)就是这样呢?
现在,事实证明,C# 编译器有某种魔法可以否认公共实例字段的存在(但见下文),但在例如 PowerShell 中,您可以这样做:
prompt> $d = [DayOfWeek]::Thursday
prompt> $d
Thursday
prompt> $d.value__ = 6
prompt> $d
Saturday
value__
可以写入该字段。
现在,要在 C# 中执行此操作,我不得不使用dynamic
,因为似乎在正常的编译时成员绑定中,C# 会假装public
实例字段不存在。当然要使用dynamic
,我们将不得不使用枚举值的装箱。
这是一个 C# 代码示例:
// 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
我认为评论不言自明。我们可以通过字段改变枚举类型的实例DayOfWeek
(可以是来自 BCL 程序集或“自制”程序集的任何枚举类型)public
。由于实例在哈希表中,并且变异导致哈希码发生变化,变异后实例在错误的“桶”中,HashSet<>
无法运行。
为什么.NET 的设计者选择制作枚举类型的实例字段public
?