C# 无法理解枚举的行为

C# 无法理解枚举的行为,c#,.net,enums,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 } 我想在rum时间程序选择第一个值为0的项目,为了确认这一点,

我在用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
}
我想在rum时间程序选择第一个值为0的项目,为了确认这一点,我给底部分配了0的值

然后我想也许程序选择了第一个值为0的项目,但按字母顺序搜索 因此,我将Top更改为Top,并更改了测试用例


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

似乎您已经意识到编译器默认从零开始计数

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)
中达到高潮

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


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

枚举只是命名某个常量

就像我们有一些水果。苹果,香蕉,橘子。我们有一个场景,如果一个婴儿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;
默认情况下,在上述条件下,您将分别在水果类型变量中获得0、1和2。如果要更改默认值,可以定义如下:

  enum Fruits {Orange = 1, Banana, Apple};
为什么这很重要。当我们假设这样的值时,我们可能会忘记序列,从而造成麻烦。但是当我们给它们命名时,我们永远不会忘记哪个值代表着水果类型=1


谢谢

但是当我给3个枚举分配相同的值时,为什么输出会发生变化(我假设左侧自动分配为0,由我显式分配为2)。好吧,通过使用相同枚举值的多个枚举值,可以使这些值彼此不可区分。如果您试图打印值的名称,则会输入未定义的行为区域,这意味着实现可以免费向您提供任何相关名称。它为什么选择一个而不是另一个是一个实现细节,可能会随时更改。返回哪个枚举名是未记录的行为。这确实是一个rum时间问题;p@LasseV.karlsen它使用二进制搜索查找要显示的名称这一事实是未记录的行为,因此OP不应依赖代码始终为重复值返回相同的名称。此外,仅向枚举添加1个值可能会更改结果。是的,这只是我使用的编译器和运行时版本的当前实现。关于这一点,我已经添加了一段。谢谢你的努力,但这并没有以任何方式回答OP的问题。
    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 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;
  enum Fruits {Orange = 1, Banana, Apple};