Являются ли типы перечисления .NET действительно изменяемыми типами значений?
Глядя с отражением на поля типа enum, я с удивлением заметил, что поле «backing instance», которое содержит фактическое значение определенного экземпляра enum, не являетсяprivate
как я бы подумал, ноpublic
, И это не былоreadonly
или. (IsPublic
правда,IsInitOnly
ложный.)
Многие люди считают «изменяемые» типы значений в системе типов .NET «злыми», поэтомупочему типы enum (например, созданный из кода 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
Я думаю, что комментарии говорят сами за себя. Мы можем изменить экземпляр типа enumDayOfWeek
(может быть любого типа enum из сборки BCL или из сборки "home-made") черезpublic
поле. Поскольку экземпляр находился в хеш-таблице, а мутация приводила к изменению хеш-кода, экземпляр находится в неправильном «корзине» после мутации, иHashSet<>
не может функционировать.
Почему разработчики .NET решили сделать поле экземпляра перечислимых типовpublic
?