欢迎光临散文网 会员登陆 & 注册

第 47 讲:枚举(三):其它枚举相关的问题

2021-07-10 20:19 作者:SunnieShine  | 我要投稿

前面已经说过了枚举的基本使用方式,以及运算符的使用。下面讲一些有关枚举类型的、前面没有提到的问题。

Part 1 枚举字段是否定义的问题

我们经常使用枚举类型把数值取出。但问题是,前文我们在表达枚举类型和整数类型进行互相转换的时候,尚未提及整个问题,那就是:如果我们将一个不存在于枚举类型里的特征值强制转换为枚举类型,那么使用它是成功的吗?是抛异常呢,还是其它情况呢?

假设我有一个枚举类型,只包含两个数值:

显然,我们也完全允许将一个超出范围的特征值(比如 2)赋值给 Gender 类型的变量上。

因为 2 是整数类型数据,所以需要强制转换。可问题在于,这个枚举类型就包含了 0 和 1 两个特征值,对吧。那么赋值 2 会产生什么现象呢?

实际上,没有任何事发生。赋值是成功的,也不会有异常,也不会中断程序,更不会出现别的现象。这样的赋值唯一和正常范围的特征值表现出来效果不一样的地方是调用 ToString 方法之后。

前者的 0 特征值对应了 Gender 类型的 Male,因此这么转换最后输出的是 Male;而后者因为没有对应的字段,因此这么做输出的结果是数字本身:2。

也就是说,如果对于一个没有对应字段的枚举类型变量进行 ToString 输出的话,实际上输出的是特征值本身;如果有的话,实际上输出的就是这个字段的名字。这是两种情况的不同点,其它的使用完全都是一样的,不会因为超出枚举定义范围而直接告诉你不能这么用,C# 没有必要限制得这么死,毕竟……没定义又不是什么无伤大雅的事情。

Part 2 特征值表达式

前文我们学习了如何使用位运算来对特殊的枚举类型进行操作。不过,实际上 C# 甚至允许你直接在特征值赋值的时候书写表达式。比如这样:

这样的感觉。虽然上面举的例子看起来有点废话,这里只是为了展示给你看这个表达式是可以写进去的。使用的字段和数字是可以直接通过加法计算得到的,这一点相当方便。

不过这里稍微注意一点。我们之前说过,<<>> 是枚举类型无法使用的运算符,但是在特征值赋值的表达式里,我们可以用,但右侧必须是一个 int 类型的字面量。

比如这样的枚举,每一个字段都是前一个字段的特征值的两倍。

但是我们在平时使用的时候,我们无法使用 << 运算符,因为这是 C# 规定禁止使用的、为数不多的运算符之一:

Part 3 负数特征值的枚举转换

可能你使用过带符号类型的整数作为特征值的基本类型表示在枚举类型的“继承关系”上。实际上,默认情况下枚举类型是使用 int 这个带符号的类型作为特征值类型的。

那么,如果我赋值 -1 作为某字段的特征值的话,我要想使用它,你可能会这么写代码:

是吧。因为我总是想将 -1 当成特征值转换给 TestEnum 上去。然而实际上,这么转换有问题,会产生一个编译器错误,并提示你改成这样:

是的,只是给 -1 加了个括号就可以了。这是 C# 团队最初设计类型系统的时候这么作了个规定。因为负数直接的字面量并不是真正意义上的字面量的一部分,实际上它还是一个表达式。只是这个负号被我们人为理解为是一个绑定在 1 上的、标记数字是负数的记号。在编程世界里,运算符在哪里都是运算符,所以 -1 是一个表达式,是一个常量表达式,并非一个字面量。

另外在 C# 的字面量系统里,数据使用字面量有很复杂的转换关系(什么“不超过一定范围的字面量,虽然是 int 类型也可以表示为较小数据类型”之类的规则)。正是因为这些规则的约束,一旦放开 -1 不添加括号直接转换的话,就会和这些细节产生一定的语义冲突。为了避免这一点,C# 不得不让你添加这个小括号,告诉你要想是负数枚举特征值的话,就必须加了小括号后再来强制转换。


第 47 讲:枚举(三):其它枚举相关的问题的评论 (共 条)

分享到微博请遵守国家法律