c# - .NET 枚举类型实际上是可变值类型吗?

标签 c# .net powershell enums immutability

仔细观察枚举类型的字段,我惊讶地发现保存枚举特定实例实际值的“支持”实例字段不是 private ,正如我所想的,但是public .它不是 readonly任何一个。 (IsPublic 真,IsInitOnly 假。)

许多人认为 .NET 类型系统中的“可变”值类型是“邪恶的”,那么为什么枚举类型(例如从 C# 代码创建的)就是这样?

现在,事实证明,C# 编译器有某种魔法可以否认公共(public)实例字段的存在(但见下文),但在例如PowerShell 你可以这样做:

prompt> $d = [DayOfWeek]::Thursday
prompt> $d
Thursday
prompt> $d.value__ = 6
prompt> $d
Saturday

字段value__可以写入。

现在,要在 C# 中执行此操作,我必须使用 dynamic因为看起来正常的编译时成员绑定(bind),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 field 。由于实例在哈希表中并且突变导致哈希码发生变化,因此实例在突变后位于错误的“桶”中,并且 HashSet<>无法运行。

为什么.NET的设计者选择将实例字段做成枚举类型public ?

最佳答案

让我试着为不熟悉枚举是如何在幕后生成的读者弄清楚这个相当令人困惑的问题。 C#代码:

enum E { A, B }

成为 IL

.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#:

struct E : System.Enum
{
    public int value__;
    public const E A = 0;
    public const E B = 1;
}

问题是:为什么魔法字段value__是公有的?

我没有参与这个设计决策,所以我必须做出有根据的猜测。我有根据的猜测是:如果该字段不公开,您如何初始化该结构的实例?

你创建了一个构造函数,然后你必须调用它,这给抖动带来了工作,而这项工作的性能成本会给你带来什么?如果答案是“它给我买了运行时间,防止我自己做一些我不应该做的愚蠢和危险的事情,而且必须非常努力地去做”那么我向你提出这不是一个令人信服的成本效益比。

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.

这比“如果你这样做时感到疼痛,那么停止这样做”这一行已经过了好几英里。

关于c# - .NET 枚举类型实际上是可变值类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17891275/

相关文章:

c# - XDocument 谷歌移动站点地图标签

c# - 查找绑定(bind)到对象的 XAML 框架元素

c# - XmlSerializer。保留空字符串属性?

c# - VS 2008 中的混合环境调试 (C# Fortran)

c# - 有什么好的 .net 数据包嗅探器吗?

适用于 ServiceNow 的 Powershell SOAP

wpf - 来自 Base64 的图像不会显示在 WPF 数据网格行中

Powershell 启动进程、超时等待、杀死并获取退出代码

.net - 通过升级 .NET Framework 提高性能

c# - 将 Task 转换为 Task<Unit> 的最有效方法?