c# - 当枚举包含具有相同值的元素时,如何将原始类型值转换为枚举值?
问题描述
我写了代码:
enum FlipRotate2dEnum : byte {
NO = 0, None = 0,
R2 = 1, RotateTwice = 1,
FX = 2, FlipX = 2,
FY = 3, FlipY = 3,
D1 = 4, ReflectDiagonal1 = 4,
D2 = 5, ReflectDiagonal2 = 5,
RC = 6, RotateClockwise = 6,
RN = 7, RotateNonClockwise = 7
}
class EnumTest {
public static void Main() {
for(byte i = 0; i < 8; ++i) {
FlipRotate2dEnum v = (FlipRotate2dEnum)i;
System.Console.WriteLine("{0} {1}", i, v);
}
}
}
我希望在输出中看到:
只有简称
0 NO
1 R2
2 FX
3 FY
4 D1
5 D2
6 RC
7 RN
或只有长名称
0 None
1 RotateTwice
2 FlipX
3 FlipY
4 ReflectDiagonal1
5 ReflectDiagonal2
6 RotateClockwise
7 RotateNonClockwise
或按字母顺序排序后首先出现的名称,在这种情况下与“仅短名称”一致。
但我没想到会看到程序显示了什么:
0 None
1 RotateTwice
2 FlipX
3 FlipY
4 ReflectDiagonal1
5 ReflectDiagonal2
6 RotateClockwise
7 RN
输出末尾的短名称。 为什么 ?
我试图重新排列 enum 中的列:
public enum FlipRotate2dEnum : byte {
None = 0, NO = 0,
RotateTwice = 1, R2 = 1,
FlipX = 2, FX = 2,
FlipY = 3, FY = 3,
ReflectDiagonal1 = 4, D1 = 4,
ReflectDiagonal2 = 5, D2 = 5,
RotateClockwise = 6, RC = 6,
RotateNonClockwise = 7, RN = 7
}
class EnumTest {
public static void Main() {
for(byte i = 0; i < 8; ++i) {
FlipRotate2dEnum v = (FlipRotate2dEnum)i;
System.Console.WriteLine("{0} {1}", i, v);
}
}
}
我再次对输出感到惊讶:
0 NO
1 R2
2 FX
3 FY
4 D1
5 D2
6 RC
7 RotateNonClockwise
为什么 ? 请向我解释这里发生了什么。
解决方案
枚举变量基本上只是一个数字,它没有R2
附加标签(例如 )。例如,FlipRotate2dEnum.RN
和FlipRotate2dEnum.RotateNonClockwise
是同一件事,因为它们具有相同的值 7。实际上,如果您这样做:
Console.WriteLine(FlipRotate2dEnum.RotateNonClockwise);
您将看到RN
作为输出。如文档中所述Enum.ToString()
如果多个枚举成员具有相同的基础值,并且您尝试根据其基础值检索枚举成员名称的字符串表示形式,则您的代码不应对该方法将返回哪个名称做出任何假设
但是如果你好奇你看到的结果是如何在内部获得的,请阅读下面的内容。
首先,基本值数组(在你的情况下 - 字节)大致像这样(但不完全像这样)获得:
byte[] values = Enum.GetValues(typeof(FlipRotate2dEnum)).Cast<byte>().ToArray();
它不包含不同的值,仅包含已排序的枚举中的所有值。所以在这种情况下 16 个值:
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7
然后获得名称数组(同样,不完全像这样,但以类似的方式)。该数组也按相应的值排序(即 - 值 0 的名称排在值 1 的名称之前等):
var names = Enum.GetNames(typeof(FlipRotate2dEnum));
它还包含 16 个名称:
NO, None, R2, RotateTwice, ...
然后,对给定值的值数组执行二进制搜索。说我们打电话FlipRotate2dEnum.RotateNonClockwise.ToString()
。它的值为 7,因此对 7 执行二进制搜索:
var index = Array.BinarySearch(values, (byte)7)
然后,结果索引用于获取名称:
var name = names[index];
现在,如果你知道二分搜索是如何工作的——你现在应该明白为什么结果不是你所期望的。使用二分搜索时,值不会按照定义的方式顺序探索,而是从中间开始搜索,每次迭代都会将搜索空间减少一半,因此在枚举声明时,您的值映射到哪个名称并不是很明显。
当然你可以通过交换RN
and来达到你想要的结果RotateNonClockwise
,但是我希望你从上面明白这不是一个好主意,更不用说你会依赖于实现细节,添加\删除新成员会很痛苦。
如评论中所述 - 如果您需要枚举的“显示”名称 - 用一些属性装饰它们并使用它。尽量避免将具有多个名称的枚举映射到相同的值,但如果这样做 - 至少不要将其视为值和名称之间的一对一映射,因为它不是这样工作的。
推荐阅读
- visual-studio - 将 directx 添加到包含和库目录会引发 300 多个错误
- j - 求使用J编程语言JHS web server as a service的例子
- python - Discord.py 机器人回复自己(它检测自己的消息)
- python - 为什么 selenium 不能与 Firefox 一起使用,但重新安装后却可以无缝运行?
- c - Linux内核中的tcp_disconnect函数是做什么的,在什么情况下会被调用?
- powershell - 是否可以混淆单个 Powershell 行?
- java - Java用表情符号替换文本
- xml - PowerShell解析XML文件
- sensors - PIR 运动传感器每小时触发一次
- git - 为什么我的 .gitattributes 文件没有阻止在 Windows 上签出文件时添加“\r”?