Цикл enum с инициализатором дает неожиданный результат

Перечисление, которое я создал, выглядит так:

enum MonthOfTheYear : byte
{
    January,
    February,
    March,
    April,
    May,
    June,
    July = 0,
    August,
    September,
    October,
    November,
    December
}

Как видите, в июле инициализатор равен 0. Это имеет некоторые интересные (побочные) эффекты: кажется, что происходит "спаривание" целочисленных значений. Февраль и август теперь имеют значения 1, март и сентябрь имеют 2 и т. Д.:

MonthOfTheYear theMonth = MonthOfTheYear.February;
Console.WriteLine(theMonth + " has integer value of " + (int)theMonth);

а также

MonthOfTheYear theMonth = MonthOfTheYear.August;
Console.WriteLine(theMonth + " has integer value of " + (int)theMonth);

четко показать это. Пока что странно, но я готов идти вперед.РЕДАКТИРОВАТЬ: я понимаю, что присвоение 0 июля заставляет индексы начать все сначала. Я не понимаю, почему они могут сосуществовать в одном и том же перечислении.

НО! ЕСЛИ я затем перебираю перечисление и выводю все базовые целочисленные значения, возникает странность.

MonthOfTheYear theMonth = MonthOfTheYear.January;

for (int i = 0; i < 12; i++)
{
    Console.WriteLine(theMonth + " has integer value of " + (int)theMonth++);
}

выходы

July has integer value of 0
February has integer value of 1
September has integer value of 2
April has integer value of 3
May has integer value of 4
June has integer value of 5
6 has integer value of 6
7 has integer value of 7
8 has integer value of 8
9 has integer value of 9
10 has integer value of 10
11 has integer value of 11

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

4 ответа

Решение

http://msdn.microsoft.com/en-us/library/system.enum.getname.aspx

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

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

Во-первых, когда вы указываете значение в определении перечисления, последующие значения нумеруются последовательно оттуда - и даже если вы указываете 0 где-то первое значение начнет нумерацию с 0, Таким образом, ваша основа byte значения:

enum MonthOfTheYear : byte
{
    January = 0, // not specified, so starts at 0
    February = 1,
    March = 2,
    April = 3,
    May = 4,
    June = 5,
    July = 0, // specified, so starts numbering from 0 again
    August = 1,
    September = 2,
    October = 3,
    November = 4,
    December = 5
}

Когда вы увеличиваете значение перечисления с ++просто увеличивает базовый byte - это не смотрит на определение enum и перейти к элементу на следующей строке!

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

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

В принципе MonthOfTheYear.February == MonthOfTheYear.August так звонишь ли ты ToString на это или просто глядя на это в отладчике, нет никакой гарантии, что одно не переключится на другое.

Используйте метод

Enum.GetName

Вот пример:

using System;

public class GetNameTest {
    enum Colors { Red, Green, Blue, Yellow };
    enum Styles { Plaid, Striped, Tartan, Corduroy };

    public static void Main() {

        Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
        Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
    }
}
// The example displays the following output:
//       The 4th value of the Colors Enum is Yellow
// 

Вы получите полное объяснение здесь:

http://msdn.microsoft.com/de-de/library/system.enum.getname.aspx

Вы явно указали июль, чтобы быть первым месяцем в перечислении. Это все портит. Попробуй это:

enum MonthOfTheYear : byte {
        January,
        February,
        March,
        April,
        May,
        June,
        July,
        August,
        September,
        October,
        November,
        December
    }

for (int i = 0; i < 12; i++) {
    Console.WriteLine(String.Format("{0} has integer value of {1}", Enum.GetName(typeof(MonthOfTheYear), i), i));
}

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

Другие вопросы по тегам