Глядя с отражением в поля типа перечисления, я с удивлением заметил, что поле экземпляра "backing", которое содержит фактическое значение конкретного экземпляра перечисления, не является private
, так как я бы думал, но public
. И это было не так. (IsPublic
true, IsInitOnly
false.)
Многие люди считают "изменчивые" типы значений в системе типа .NET "злыми", поэтому почему типы перечисления (например, созданные из кода С#) только это?
Теперь, как оказалось, у компилятора С# есть какая-то магия, которая отрицает существование поля публичного экземпляра (но см. ниже), но, например, PowerShell вы можете сделать это:
prompt> $d = [DayOfWeek]::Thursday
prompt> $d
Thursday
prompt> $d.value__ = 6
prompt> $d
Saturday
Поле value__
можно записать в.
Теперь, чтобы сделать это в С#, мне пришлось использовать dynamic
, потому что кажется, что при нормальной привязке элемента компиляции С# делает вид, что поле экземпляра public
не существует. Конечно, чтобы использовать dynamic
, нам нужно будет использовать бокс для значения перечисления.
Здесь пример кода С#:
// 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
?