在阅读Jon Skeet对这个特定问题的答案How can I make it so my class variables can only be set to one of three choices?时,我学到了一些我在C#中没有意识到的新东西,我想是CLR类型系统。
这是合法的原因是什么:
public enum Tests
{
Zero = 0,
One,
Two
}
var nonExistantTestsValue = (Tests)1000;
这将编译完全正常,但我没有看到为什么它应该是这样的原因。就我所见,整个枚举点是将指定类型的给定变量的值限制为一定数量的选项。
如果enum
定义所施加的限制很容易被破坏,那么除了可读性问题之外还有什么意义呢?你可以使用反射来确定它是一个有效的值,但为什么不在编译时完成呢?
可能有一个很好的理由让它以它的方式工作,但我没有看到它。
答案 0 :(得分:5)
Enumerations本质上是唯一的类型,允许您将符号名称分配给整数值。它们不用于限制变量的允许值......
答案 1 :(得分:3)
如果枚举定义所施加的限制很容易被打破,那么
是什么意思
我认为枚举抽象的设计并未考虑限制或保证。我认为它的设计考虑了便利性和可维护性
很好的理由:
如果您不想现在看到简单的事实,请跳过第一颗子弹 <子> 子>
... then what's the point
这样的短语会为我触发]
(记住CLR函数可以从任何地方调用,而不仅仅是C#,而不仅仅是你的程序集)
答案 2 :(得分:2)
当枚举不限于这些值时,你可以做些什么呢?
Flags就是其中一个例子:
[Flags]
enum MyFlag
{
a,
b,
c
}
现在你可以做位操作了:
MyFlag flags = MyFlag.a|MyFlag.b;
答案 3 :(得分:1)
允许任何值,因为您可以使用“Flags”属性标记枚举。这意味着你可以通过对枚举本身的各个成员进行OR运算来组成任何值。 基本上,编译器不够智能,无法处理使用枚举的任何可能方式。
编辑:找到Eric Lippert的上一篇文章:Why does casting int to invalid enum value NOT throw exception?
答案 4 :(得分:1)
我不知道这个设计决定的原因,但我们可以看看它的一些后果。
让我们看一下枚举的IL表示:
.class private auto ansi sealed MyEnum
extends [mscorlib]System.Enum
{
// Fields
.field public specialname rtspecialname int32 value__
.field public static literal valuetype MyEnum Value0 = int32(0)
.field public static literal valuetype MyEnum Value1 = int32(1)
.field public static literal valuetype MyEnum Value2 = int32(2)
}
首先我们注意到它是一个值类型,因此(MyEnum)0
必须有效。其次,我们看到枚举的可能值只是const
s,运行时级别的枚举与整数文字的赋值兼容。
枚举常量通常变为整数字面值。因此,如果您想要防止出现无效的枚举,则需要在从枚举转换时引入昂贵的运行时检查,或者进行非平凡的交叉程序集加载时间检查,以确保烘焙到另一个程序集中的枚举文字是有效的。
另一件事是可以创建由long支持的枚举。但多头的一个属性是他们的任务不能保证是原子的。因此,保证基于long
的枚举的值有效是很难的。
enum MyLongEnum:long
{
Value1=0x0101010102020202,
Value2=0x0303030304040404
}
如果您从多个线程分配给这样的枚举,即使您从未分配过无效值,也可能会出现无效的混合值。
还有一个简单的解决方法来获取安全的枚举:使用具有私有构造函数的类和静态只读字段或属性来获取可能的值。这样你就失去了整数转换,文字和非空性,但获得了类型安全性和更好的版本控制。