通过反射,在枚举类型的字段中查看,我惊讶地发现,保存枚举的特定实例的实际值的"backing"实例字段不是 private
,正如我所想的那样,但 public
. 它也不是 readonly
. ( IsPublic
true, IsInitOnly
false . )
许多人认为.NET类型系统"evil"中的"mutable"值类型,所以 why are the enum types (例如从C#代码创建) just that?
现在,事实证明,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
我认为这些评论不言而喻 . 我们可以通过 public
字段来改变枚举类型 DayOfWeek
的实例(可以是来自BCL程序集或来自"home-made"程序集的任何枚举类型) . 由于实例位于哈希表中并且突变导致哈希码的更改,因此实例在突变后的错误"bucket"中,并且 HashSet<>
无法运行 .
Why did the designers of .NET choose to make the instance field of enum types public?
1 回答
让我试着让那些不熟悉幕后产生枚举的读者理解这个相当令人困惑的问题 . C#代码:
成为IL
或者,要再次在C#中重写,枚举等效于以下伪C#:
问题是:为什么神奇的领域
value__
是公开的?我没有参与这个设计决定,所以我必须做出有根据的猜测 . 我受过教育的猜测是:如果字段不公开,如何初始化结构的实例?
你创建了一个构造函数,然后你必须调用它,这就是为抖动提供工作,这项工作的性能成本会给你带来什么?如果答案是“它给我买了运行时阻止我做一些愚蠢和危险的事情,我本来不应该做的事情,而且必须要努力工作”然后我向你提出这不是一个引人注目的成本效益比 .
那是几英里之后的“如果你那么伤害那么 stop doing that ”行 .