无法理解Enums的行为

时间:2014-09-08 05:28:29

标签: c# .net enums

我在C#中练习枚举,我无法理解这些

的输出
void Main()
{
    MyEnum a = MyEnum.Top;
    Console.WriteLine(a);
}

对于此测试,我的枚举和输出是

enum MyEnum
{
    Left, Right, Top, Bottom // Top
}

enum MyEnum
{
    Left, Right, Top = 0, Bottom // Left
}

我认为在朗姆酒时间程序中选择值为0的第一项,以确认我将值0分配给底部

enum MyEnum
{
    Left, Right, Top = 0, Bottom = 0 // Bottom
}

然后我想也许程序选择值为0的第一项,但按字母顺序搜索 所以我将 顶部更改为 ATop 并更改了测试用例

void Main()
{
    MyEnum a = MyEnum.ATop;
    Console.WriteLine(a);
}

enum MyEnum
{
    Left, Right, ATop = 0, Bottom = 0 // Bottom
}

enum MyEnum
{
    Left, Right, ATop = 0, Bottom // Left
}

我知道没有人以这种方式使用枚举,但我想知道Enum的这种特殊行为。

2 个答案:

答案 0 :(得分:7)

好像你已经发现编译器默认开始计数为零。

enum MyEnum
{
    Left, Right, Top = 0, Bottom = 0 // Bottom
}

转换为此

.class nested private auto ansi sealed MyEnum
    extends [mscorlib]System.Enum
{
    .field public specialname rtspecialname int32 value__
    .field public static literal valuetype X/MyEnum Left = int32(0)
    .field public static literal valuetype X/MyEnum Right = int32(1)
    .field public static literal valuetype X/MyEnum Top = int32(0)
    .field public static literal valuetype X/MyEnum Bottom = int32(0)
}

运行时实际上大部分时间都与底层类型一起使用。所以有趣的是,这就是

static void Main()
{
    MyEnum a = MyEnum.Top;
    Console.WriteLine(a);

    Console.ReadKey();
}

甚至不使用实际的枚举成员:

.method private hidebysig static 
    void Main () cil managed 
{
    .maxstack 1
    .entrypoint
    .locals init (
        [0] valuetype X/MyEnum a
    )

    IL_0000: nop
    IL_0001: ldc.i4.0
    IL_0002: stloc.0
    IL_0003: ldloc.0
    IL_0004: box X/MyEnum
    IL_0009: call void [mscorlib]System.Console::WriteLine(object)
    IL_000e: nop
    IL_000f: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_0014: pop
    IL_0015: ret
}

它只使用值0.决定使用Console.WriteLine打印的名称从System.Enum.ToString开始,System.Type.GetEnumName(object)中的高潮开始。

public virtual string GetEnumName(object value)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }
    if (!this.IsEnum)
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnum"), "enumType");
    }
    Type type = value.GetType();
    if (!type.IsEnum && !Type.IsIntegerType(type))
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeEnumBaseTypeOrEnum"), "value");
    }
    Array enumRawConstantValues = this.GetEnumRawConstantValues();
    int num = Type.BinarySearch(enumRawConstantValues, value);
    if (num >= 0)
    {
        string[] enumNames = this.GetEnumNames();
        return enumNames[num];
    }
    return null;
}

正如您所看到的,搜索要打印的名称的实际方法是通过字段名称(通过反射找到)进行二进制搜索。

这只是当前的实现,但可能因不同的编译器和/或运行时版本而有所不同。语言规范不保证上述代码的任何特定顺序或结果。

答案 1 :(得分:-1)

Enum只不过是命名一些常数。

就像我们有一些成果。苹果,香蕉,橙。我们有一个场景,如果一个婴儿1岁,它将获得橙色,如果2将获得香蕉,如果3将获得苹果。那我们怎么写呢?

一个解决方案就像:

    int fruiteType = 0;
    if(ageOfBaby == 1)
        fruiteType == 1;//assuming Orange = 1; 
    if(ageOfBaby == 2)
        fruiteType == 2;//assuming Banana = 2; 
    if(ageOfBaby == 3)
        fruiteType == 3;//assuming Apple = 3; 

我们可以巧妙地使用Enum。喜欢:

    enum Fruits {Orange, Banana, Apple};

    int fruiteType = 0;
    if(ageOfBaby == 1)
        fruiteType == (int)Fruits.Orange;
    if(ageOfBaby == 2)
        fruiteType == (int)Fruits.Banana;
    if(ageOfBaby == 3)
        fruiteType == (int)Fruits.Apple;

默认情况下,您将分别在上述条件下的fruiteType变量中获得0,1,2。如果你想改变默认值,你可以定义如下:

  enum Fruits {Orange = 1, Banana, Apple};

为什么这很重要。当我们假设这些值时,我们可能会忘记序列,从而产生麻烦。但是当我们命名它们时,我们永远不会忘记fruitType = 1的哪个值。

由于