即使在枚举中没有定义有效值,为什么允许枚举转换

时间:2011-07-11 12:37:47

标签: c# enums type-systems

在阅读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定义所施加的限制很容易被破坏,那么除了可读性问题之外还有什么意义呢?你可以使用反射来确定它是一个有效的值,但为什么不在编译时完成呢?

可能有一个很好的理由让它以它的方式工作,但我没有看到它。

5 个答案:

答案 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
}

如果您从多个线程分配给这样的枚举,即使您从未分配过无效值,也可能会出现无效的混合值。


还有一个简单的解决方法来获取安全的枚举:使用具有私有构造函数的类和静态只读字段或属性来获取可能的值。这样你就失去了整数转换,文字和非空性,但获得了类型安全性和更好的版本控制。