Как неоднозначные значения перечисления разрешены в С#?

Я проверил раздел спецификации языка С# относительно перечислений, но не смог объяснить вывод для следующего кода:

enum en {
    a = 1, b = 1, c = 1,
    d = 2, e = 2, f = 2,
    g = 3, h = 3, i = 3,
    j = 4, k = 4, l = 4
}

en[] list = new en[] {
    en.a, en.b, en.c,
    en.d, en.e, en.f,
    en.g, en.h, en.i,
    en.j, en.k, en.l
};
foreach (en ele in list) {
    Console.WriteLine("{1}: {0}", (int)ele, ele);
}

Он выводит:

c: 1
c: 1
c: 1
d: 2
d: 2
d: 2
g: 3
g: 3
g: 3
k: 4
k: 4
k: 4

Теперь, почему он выбирает третий "1", первый "2" и "3", а второй "4"? Это поведение undefined, или я пропущу что-то очевидное?

Ответ 1

Это задокументировано как недокументированное поведение.

Возможно, что-то в том, как написан код, который будет каждый раз получать одно и то же, но документация Enum.ToString утверждает следующее:

Если несколько элементов перечисления имеют одно и то же базовое значение, и вы пытаетесь получить строковое представление имени члена перечисления на основе его базового значения, ваш код не должен делать каких-либо предположений о том, какое имя возвращает метод.

(мой акцент)

Как упоминалось в комментарии, другая среда выполнения .NET может возвращать разные значения, но вся проблема с недокументированным поведением заключается в том, что она подвержена изменению без какой-либо (по-видимому) веской причины. Он может меняться в зависимости от погоды, времени, настроения программиста или даже в исправлении для среды выполнения .NET. Вы не можете полагаться на недокументированное поведение.

Обратите внимание, что в вашем примере ToString это именно то, что вы хотите посмотреть, поскольку вы печатаете значение, которое, в свою очередь, преобразует его в строку.

Если вы попытаетесь выполнить сравнение, все значения перечисления с одним и тем же базовым численным значением эквивалентны, и вы не можете определить, какой из них вы сохранили в переменной в первую очередь.

Другими словами, если вы это сделаете:

var x = en.a;

нет возможности впоследствии вывести, что вы написали en.a, а не en.b или en.c, поскольку все они сравниваются равными, все они имеют одинаковое базовое значение. Ну, не нужно создавать программу, которая читает собственный источник.