I was practicing enums in C#, and I am not able to understand the output of these
void Main()
{
MyEnum a = MyEnum.Top;
Console.WriteLine(a);
}
For this test my enum and output are
enum MyEnum
{
Left, Right, Top, Bottom // Top
}
enum MyEnum
{
Left, Right, Top = 0, Bottom // Left
}
I thought at rum time program chooses the 1st item with value 0, to confirm this I assigned value of 0 to Bottom
enum MyEnum
{
Left, Right, Top = 0, Bottom = 0 // Bottom
}
Then I thought maybe program chooses the 1st item with value 0 but searches alphabetically so I changed Top to ATop and changed the test case
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
}
I know nobody uses enum in this way, but I want to know this particular behavior of Enum.
Seems like you figured out already that the compiler starts counting at zero by default.
enum MyEnum
{
Left, Right, Top = 0, Bottom = 0 // Bottom
}
gets translated to this
.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)
}
The runtime actually works with the underlying types most of the time. So the funny thing is that this here
static void Main()
{
MyEnum a = MyEnum.Top;
Console.WriteLine(a);
Console.ReadKey();
}
doesn't even use the actual enum member:
.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
}
It just uses the value 0. The decision making of which name to print out with Console.WriteLine
begins in System.Enum.ToString
and climaxes in 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;
}
As you can see the actual way to search for the name to print is a binary search through the field names (found by reflection).
This is just the current implementation, though and might differ with different compilers and/or runtime versions. The language specification doesn't guarantee any particular order or outcome for code like the one above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With