Получение имен элементов из перечислений с несколькими нулевыми значениями - PullRequest
7 голосов
/ 31 января 2012

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

Есть ли способ изолировать имя ненулевого значения, не прибегая к манипуляции или отражению строки?

//all of the following output "Nada, Zilch, One"
Console.WriteLine(TestEnum.One);
Console.WriteLine(Convert.ToString(TestEnum.One));
Console.WriteLine(TypeDescriptor.GetConverter(typeof(TestEnum))
                      .ConvertToString(TestEnum.One));

[Flags]
enum TestEnum
{
    Zero = 0,
    Nada = 0,
    Zilch = 0,
    One = 1
}

Редактировать

Я понимаю, что использование нескольких элементов с одинаковым значением не рекомендуется, однако рассматриваемое перечисление определено в устаревшей сборке, которую я могу 'т изменить.На самом деле в mscorlib v4 существует 12 открытых перечислений, которые нарушают эту рекомендацию, что определяется следующим простым запросом LINQ:

var types = typeof (void).Assembly.GetTypes()
    .Where(type => type.IsEnum &&
                   type.IsPublic &&
                   Enum.GetValues(type).Cast<object>()
                       .GroupBy(value => value)
                       .Any(grp => grp.Count() > 1))
    .ToList();

Ответы [ 3 ]

1 голос
/ 31 января 2012

Вот один из вариантов. Это работает, но это немного некрасиво. Переменные значений / имен не изменятся, поэтому их нужно вычислять только один раз.

Предположим, у вас есть немного более сложное перечисление, например:

[Flags]
public enum TestEnum
{
    Zero = 0,
    Nada = 0,
    Zilch = 0,
    One = 1,
    Two = 2,
    Three = 3,
    Four = 4
}

Вот код, который вы можете использовать:

var input = TestEnum.One | TestEnum.Two;
var values = (TestEnum[]) Enum.GetValues(typeof (TestEnum));
var names = Enum.GetNames(typeof (TestEnum));
var result = values
    .Select((value, index) =>
            input == value || (value != 0 && (input & value) == value)
                ? names[index]
                : null)
    .Where(name => name != null);
var text = string.Join(", ", result);
Console.WriteLine(text);
1 голос
/ 31 января 2012

Хорошо, сначала Microsoft настоятельно рекомендует против этого . Некоторые из сильных слов, которые я слышал, они используют для чего-то, что они не применяют при компиляции:

Старайтесь не устанавливать значение перечисления флагов в ноль, если только это значение не указывает на то, что все флаги сброшены. Такое значение должно быть названо соответствующим образом, как описано в следующем руководстве ... Назовите нулевое значение перечисления флагов Нет. Для перечисления флагов значение должно всегда означать, что все флаги очищены.

Хорошо, так почему это происходит? С этот вопрос Я так понимаю Enum.ToString ведет себя странно:

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

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

Можете ли вы просто щелкнуть правой кнопкой мыши-> refactor-> переименовать их, а затем удалить остальные? Это кажется проще и меньше против того, что Microsoft рекомендует.

0 голосов
/ 31 января 2012

Предполагая, что у вас есть немного более сложное перечисление, такое как:

[Flags]
public enum TestEnum
{
    Zero = 0,
    Nada = 0,
    Zilch = 0,
    One = 1,
    Two = 2,
    Four = 4,
}

Вы можете реализовать простой метод, который возвращает вам строковое значение, например:

public static string TestEnumToString(TestEnum value)
{
    var result = new List();

    if (value == TestEnum.Zero)
    {
        result.Add("Zero");
    }
    if (value == TestEnum.Nada)
    {
        result.Add("Nada");
    }
    if (value == TestEnum.Zilch)
    {
        result.Add("Zilch");
    }
    if ((value & TestEnum.One) != 0)
    {
        result.Add("One");
    }
    if ((value & TestEnum.Two) != 0)
    {
        result.Add("Two");
    }
    if ((value & TestEnum.Four) != 0)
    {
        result.Add("Four");
    }

    return string.Join(",", result);
}
...