无法理解枚举的行为
本文关键字:枚举 | 更新日期: 2023-09-27 18:21:05
我在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的第一个项目,但按字母顺序搜索所以我将Top更改为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 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;
}
正如您所看到的,搜索要打印的名称的实际方法是通过字段名称进行二进制搜索(通过反射找到)。
不过,这只是当前的实现,不同的编译器和/或运行时版本可能会有所不同。语言规范并不能保证像上面这样的代码有任何特定的顺序或结果。
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。
感谢