I do not know the reasons for this design decision, but we can look at some of its consequences.
Take a look at the IL enumeration view:
.class private auto ansi sealed MyEnum extends [mscorlib]System.Enum {
First, note that this is a value type and therefore (MyEnum)0 must be valid. Secondly, we see that the possible values ββof the enumerations are just const and that the enumerations at the run level are assignments compatible with whole literals.
Continuum constants usually become whole letters. Therefore, if you want to prevent the occurrence of invalid enumerations, you will need to enter either expensive runtime checks when converting from an enumeration, or non-trivial cross-assembly time checks to make sure that enumeration literals baked in another assembly are valid.
Another thing is that you can create enumerations supported by long ones. But one property of longitude is that their purpose is not guaranteed to be atomic. Thus, ensuring that the value of en long is enumerated is difficult.
enum MyLongEnum:long { Value1=0x0101010102020202, Value2=0x0303030304040404 }
If you have assigned such an enumeration from multiple threads, you can get a mixed value that is invalid even if you never assigned an invalid value.
There is also an easy workaround for getting safe enumerations: use a private constructor class and static fields or readonly properties for possible values. This way you lose whole conversions, literals, and non-nullability, but you get type safety and better version control.
source share