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.