简体   繁体   English

当枚举包含具有相同值的元素时,如何将原始类型值转换为枚举值?

[英]How to convert primitive type value to enum value, when enum contains elements with the same values?

I wrote the code : 我写了代码:

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);
        }
    }
}

and I expect to see in ouput : 我希望在输出中看到:

only short names 只有短名

0 NO
1 R2
2 FX
3 FY
4 D1
5 D2
6 RC
7 RN

or only long names 或只是长名

0 None
1 RotateTwice
2 FlipX
3 FlipY
4 ReflectDiagonal1
5 ReflectDiagonal2
6 RotateClockwise
7 RotateNonClockwise

or names that occur first, after sorting in alphabetical order, which in this case coincides with "only short names". 或按字母顺序排序后首先出现的名称,在这种情况下与“仅短名称”重合。

But I did not expect to see what the program showed up : 但我没想到会看到该节目出现的内容:

0 None
1 RotateTwice
2 FlipX
3 FlipY
4 ReflectDiagonal1
5 ReflectDiagonal2
6 RotateClockwise
7 RN

Short name at the end of the output. 输出结尾的短名称。 ¿ Why ? ¿为什么?


I tried to rearrange columns in 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);
        }
    }
}

and again I got a surprise in the output : 我再次对输出感到惊讶:

0 NO
1 R2
2 FX
3 FY
4 D1
5 D2
6 RC
7 RotateNonClockwise

¿ Why ? ¿为什么? Please, explain to me what's going on here. 请向我解释这里发生了什么。

Enum variable is basically just a number, it doesn't have a label (such as R2 ) attached to it. 枚举变量基本上只是一个数字,它没有附加标签(如R2 )。 For example, FlipRotate2dEnum.RN and FlipRotate2dEnum.RotateNonClockwise are the same thing, because they have the same value 7. Actually if you do: 例如, FlipRotate2dEnum.RNFlipRotate2dEnum.RotateNonClockwise是相同的,因为它们具有相同的值7.实际上,如果你这样做:

Console.WriteLine(FlipRotate2dEnum.RotateNonClockwise);

You will see RN as output. 您将看到RN作为输出。 As stated in documentation of Enum.ToString() Enum.ToString()文档中Enum.ToString()

If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return 如果多个枚举成员具有相同的基础值,并且您尝试根据其基础值检索枚举成员名称的字符串表示形式,则您的代码不应对该方法将返回的名称做出任何假设

But if you are curious how exactly result you see is obtained internally, please read below. 但是如果你很好奇你所看到的确切结果是如何在内部得到的,请阅读以下内容。

First, array of underlying values (in your case - bytes) is obtained roughly like this (but not exactly like this): 首先,基本值的数组(在您的情况下 - 字节) 大致是这样获得的(但不完全像这样):

byte[] values = Enum.GetValues(typeof(FlipRotate2dEnum)).Cast<byte>().ToArray();

It does not contain distinct values, just all values in enum, sorted. 它不包含不同的值,只包含枚举中的所有值,已排序。 So in this case 16 values: 所以在这种情况下16个值:

0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7

Then array of names is obtained (again, not exactly like this, but in a similar way). 然后获得名称数组(再次,不完全像这样,但以类似的方式)。 This array is also sorted, by corresponding value (that is - names for values 0 go before names for values 1 etc): 此数组也按相应的值排序(即 - 值0的名称在值1的名称前面等):

var names = Enum.GetNames(typeof(FlipRotate2dEnum));

It also contains 16 names: 它还包含16个名称:

NO, None, R2, RotateTwice, ...

Then, binary search is performed over array of values for the given value. 然后,对给定值的值数组执行二进制搜索 Say we call FlipRotate2dEnum.RotateNonClockwise.ToString() . 假设我们调用FlipRotate2dEnum.RotateNonClockwise.ToString() It has value 7, so binary search is performed for 7: 它的值为7,因此对7执行二进制搜索:

var index = Array.BinarySearch(values, (byte)7)

Then, resulting index is used to get name: 然后,结果索引用于获取名称:

var name = names[index];

Now, if you know how binary search works - you should now understand why results are not quite what you expect. 现在,如果你知道二进制搜索是如何工作的 - 你现在应该理解为什么结果不是你所期望的。 With binary search values are not explored sequentially in the way they are defined, instead search starts in the middle and reduces search space in a half with every iteration, so it's not very obvious to which name your value is mapped while starring at enum declaration. 对于二进制搜索值,不会按照它们的定义方式按顺序进行探索,而是从中间开始搜索,并在每次迭代时将搜索空间减少一半,因此在枚举枚举声明时,您的值映射到哪个名称并不是很明显。

Of course you can achieve your desired result by just swapping RN and RotateNonClockwise , but I hope you understand from the above that it's not a great idea, not to mention you would rely on implementation detail, and addind\\removing new members will be a pain. 当然你可以通过交换RNRotateNonClockwise来达到你想要的效果,但我希望你从上面了解到这不是一个好主意,更不用说你会依赖于实现细节,而addind \\删除新成员会很痛苦。

As stated in comments - if you need "display" names for your enums - decorate them with some attribute and use it. 如评论中所述 - 如果您需要为您的枚举“显示”名称 - 用某些属性装饰它们并使用它。 Try to avoid enums with multiple names mapping to the same value, but if you do - at least don't think about that as one-to-one mapping between value and name, because that's not how it works. 尽量避免使用多个名称映射到相同值的枚举,但如果这样做 - 至少不要将其视为值和名称之间的一对一映射,因为这不是它的工作原理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM