c# имена перечислений для фильтрации в DropDownList вместо значения

У меня есть список перечислений, который включает перечисление по умолчанию.

public enum Fruits { Default = Banana, 
                    Banana = 1, 
                    Orange = 2, 
                    Grapefruit = 3 }

Мне нужно заполнить раскрывающийся список, который исключает поле по умолчанию.

Html.DropDownList("fruitSelector", 
                Enum.GetValues(typeof(Fruits)).Cast<Fruits>()
                    .OrderBy(o => o.GetDescription())
                    .Where(o => o != Fruits.Default)
                    .Select(o => new SelectListItem() {Text = o.GetDescription(), Value = ((int) o).ToString()}), "-- All Fruits --",
                new {@class = "form-control", @aria_describedby="sizing-addon1"})

когда я пытаюсь отфильтровать Fruits.Default, он удаляет ОБА по умолчанию и Banana. Как я могу выполнить сравнение фильтров, где я удаляю только значение по умолчанию?

[[ИСПРАВЛЕНИЕ]] это перечисление дублирует мою проблему. Я честно не понимаю разницы.

public enum Fruits
    {
        Default = Peaches,
        Peaches = 1,
        Bananas = 2,
        Grapefruit = 3,
        Apple = 101,
        Watermellon = 102
    }

or

public enum Fruits2
{
    Default = Mangos,
    Mangos = 1,
    Dates = 2,
    Figs = 3,
    Apples = 101,
    Limes = 102,
    Grapes = 103
}

person user1161137    schedule 15.08.2017    source источник
comment
Компилируется ли приведенный выше код? Или у вас есть метод расширения, не показанный здесь? Иначе как бы o.GetDescription() компилировался без ошибок?   -  person Sach    schedule 16.08.2017
comment
stackoverflow.com/questions/30467519/   -  person Dan Orlovsky    schedule 16.08.2017
comment
@Sach ya, это способ получить пользовательскую аннотацию Description. вы можете это исключить.   -  person user1161137    schedule 16.08.2017


Ответы (2)


Я не думаю, что то, что вы пытаетесь сделать, возможно как есть. Проблема в вашей структуре Enum.

public enum Fruits
{
    Default = Peaches,
    Peaches = 1,
    Bananas = 2,
    Grapefruit = 3,
    Apple = 101,
    Watermellon = 102
}

Вы говорите, что значение Default равно Peaches, из которых значение, в свою очередь, равно 1. Что по сути то же самое, что и (B равно Peaches, а A равно Default:

int B = 1;
int A = B;

Поэтому, когда мы используем Enum.Parse(), он обрабатывает оба значения одинаково и выбирает первое значение. Вы поймете, когда посмотрите на следующий сценарий. Запустите следующий код с вашим текущим Enum:

var deflt = Enum.Parse(typeof(Fruits), Fruits.Default.ToString());
var peach = Enum.Parse(typeof(Fruits), Fruits.Peaches.ToString());
Console.WriteLine(deflt);
Console.WriteLine(peach);

Выход будет:

По умолчанию

По умолчанию

Затем измените свой Enum на это:

public enum Fruits
{
    Peaches = Default ,
    Default = 1,
    Bananas = 2,
    Grapefruit = 3,
    Apple = 101,
    Watermellon = 102
}

И снова запустите приведенные выше две строки кода. Ваш результат на этот раз будет:

Персики

Персики

То есть Parse() выбирает первый определенный Enum, когда есть равенство, как у вас.

ИЗМЕНИТЬ:

Приведенное выше объяснение немного неверно, как указано в комментариях Джорджа Александрии ниже. См. его объяснение: У вас разные выходные данные при использовании Peaches = Default , Default = 1 и Default = Peaches, Peaches = 1, потому что вы вызываете Enum.ToString в Console.WriteLine. Если вы посмотрите на var deflt, var peach, вы увидите, что они одинаковы в обоих случаях, и это значение, имя которого стоит первым в алфавитном порядке.


Но есть обходной путь. Из вашего первоначального примера кода я понял, что вам нужен список Enum, их описания и их числовые значения, я прав? Итак, я бы сначала просто взял список строк, исключая Default, что довольно просто. Затем выполните итерацию по списку строк и добавьте в список объектов класса SelectListItem.

var res = Enum.GetNames(typeof(Fruits))
    .Where(x => x != "Default");

List<SelectListItem> list = new List<SelectListItem>();
foreach (string fruit in res)
{
    string desc = EnumHelper<Fruits>.GetEnumDescription(fruit); // This is a utility method I use. You can get the description using your extension method.
    int val = (int)Enum.Parse(typeof(Fruits), fruit);
    list.Add(new SelectListItem { enumName = fruit, enumDesc = desc, enumVal = val });
}

И если вы должны иметь этот OrderBy, после создания списка SelectListItem отсортируйте его еще раз по Description.

person Sach    schedule 16.08.2017
comment
У вас разные выходные данные при использовании Peaches = Default , Default = 1, и Default = Peaches, Peaches = 1,, потому что вы вызываете Enum.ToString в Console.WriteLine. Если вы посмотрите на var deflt, var peach, вы увидите, что они одинаковы в обоих случаях, и это значение, название которого стоит первым в алфавитном порядке - person George Alexandria; 16.08.2017
comment
Это интересно знать! Спасибо! Я обновлю свой ответ этой информацией. - person Sach; 16.08.2017
comment
перечисление уже используется и не может быть изменено. плюс нет особого смысла изменять перечисления таким образом. Причина, по которой используется значение по умолчанию, я считаю, что существующий код состоит в том, чтобы иметь простой способ изменить значение по умолчанию, если это необходимо. но значение существующих значений не может измениться. поэтому сделать персик = по умолчанию - это большая разница, чем сказать по умолчанию = персик. Значит, нет другого способа сделать это, кроме как с помощью вашего обходного пути? хм - person user1161137; 17.08.2017
comment
@Sach, как мне заставить работать метод расширения вместо того, что вы написали для получения описания. это означает, что нет перечисления, как вы это сделали, так как же можно использовать описание расширения, которое у меня есть. ссылаясь на эту строку: string desc = EnumHelper‹Fruits›.GetEnumDescription(fruit); - person user1161137; 17.08.2017
comment
Я предположил, что у вас есть собственный метод расширения, что вы и сказали в ответ на один из моих предыдущих комментариев. Я не уверен в методах расширения, но вы можете использовать метод утилиты, который я обычно использую, который я также получил изначально из ответа SO. - person Sach; 17.08.2017
comment
да, это метод расширения. но он расширяет тип перечисления. я просто не знаю, как вписать это в ваше решение. прежде чем я делал это в предикате, который принимал тип перечисления. но у вас есть строка, с которой вы работаете. - person user1161137; 17.08.2017
comment
На самом деле вам не нужен метод расширения. Просто вызовите метод утилиты, который я предоставил, следующим образом: string desc = EnumHelper<Fruits>.GetEnumDescription(fruit); - person Sach; 17.08.2017
comment
все еще возникают проблемы с попаданием в раскрывающийся список. Есть ли альтернативный подход к добавлению аннотации атрибута к перечислению, чтобы его можно было ИСКЛЮЧИТЬ из выбора? Кажется, так будет лучше. - person user1161137; 17.08.2017
comment
Какая у вас проблема? Потому что этот код, в конце концов, в любом случае делает именно то, что вы делали в первую очередь, поскольку он создает список объектов SelectListItem. - person Sach; 17.08.2017
comment
я попробовал ваше решение, и я все еще получаю значение по умолчанию в списке. - person user1161137; 17.08.2017
comment
@ user1161137 это просто невозможно. Вот полный код, который я запустил, и он дает ожидаемые результаты. dotnetfiddle.net/GFcklC - person Sach; 17.08.2017
comment
да, я вижу, что ваш пример работает... в целом этот процесс кажется очень ненадежным, потому что, как только вы даже перемещаете перечисления (положение в списке) или вводите дополнительные перечисления (с уникальными значениями), он ломается. Я добавлю в описание еще одно фруктовое перечисление... чтобы доказать свою точку зрения... но ваше решение должно работать, потому что речь идет всего лишь о том, чтобы избавиться от перечисления по умолчанию, но это не так. - person user1161137; 18.08.2017
comment
не понимаю ... только что посмотрел ваш образец и вижу в списке вывода значение по умолчанию. tx за вашу помощь, кстати.. я знаю, что это отнимает у вас время. - person user1161137; 18.08.2017
comment
я вижу, вы удалили свой комментарий, показывающий второй образец ... поэтому я полагаю, вы подтвердили, что он тоже не работает. - person user1161137; 18.08.2017
comment
Да, это не работает для некоторых и работает для других. И я понял, что настоящая проблема заключается в равенстве в вашем перечислении, и оно испортилось, когда используется метод Parse(). Могу я спросить, зачем вам это равенство? Вам было бы лучше, если бы вы использовали чистое перечисление. - person Sach; 18.08.2017
comment
для удобства в коде, где в настоящее время, когда код попадает, используется это конкретное значение.. потому что в будущем другое значение может использоваться как «по умолчанию», и вы не хотите проходить через все местоположения в коде, чтобы обновить новое значение по умолчанию. он использовался во многих местах таким образом. - person user1161137; 18.08.2017
comment
хорошо, это работает, если вы замените свою строку .Where(x =› x != Fruits.Default.ToString()); с темп. = по умолчанию; var res = Enum.GetNames (typeof (Fruits)); res = res.Where(e =› e != temp).ToArray(); вместо того, чтобы получать ключ по умолчанию из перечисления, мы уже знаем, что это значение по умолчанию, которое мы хотим удалить, поэтому явное помещение его в строку гарантирует, что мы имеем дело с правильным именованным перечислением... тогда остальная часть вашего кода работает. - person user1161137; 18.08.2017
comment
@Sach обновите свой ответ до буквальной строки «По умолчанию», а не в зависимости от Fruits.Default.ToString () ... и я приму ответ. - person user1161137; 18.08.2017
comment
Готово. Но я все еще думаю, что ваша структура enum уязвима для многих непредвиденных последствий, и ее следует избегать, если это возможно. - person Sach; 18.08.2017
comment
также .. вы должны добавить этот Enum Helper к ответу на случай, если это понадобится кому-то еще. нет гарантий, что эта часть будет доступна в будущем, если она не является частью этого ответа. - person user1161137; 19.08.2017

Вы должны сравнивать значения enum по их именам, потому что Default и Banana равны. Поэтому просто попробуйте получить имена, отфильтровать их и разобрать на значения.

var res = Enum.GetNames(typeof(Fruits))
              .Where(o => o != nameof(Fruits.Default))
              .Select(o => Enum.Parse(typeof(Fruits), o))
              .Cast<Fruits>().ToList();

Это ваш полный пример:

Html.DropDownList("fruitSelector",
            Enum.GetNames(typeof(Fruits))
                .Where(o => o != nameof(Fruits.Default))
                .Select(o => Enum.Parse(typeof(Fruits), o)).Cast<Fruits>()
                .OrderBy(o => o.GetDescription())
                .Select(o => new SelectListItem() { Text = o.GetDescription(), Value = ((int)o).ToString() }), "-- All Fruits --",
            new { @class = "form-control", @aria_describedby = "sizing-addon1" })
person George Alexandria    schedule 15.08.2017
comment
это, кажется, работает с первым перечислением, которое я вставил... но я заметил, что это перечисление не повторяет мою проблему... я добавил второе перечисление, которое немного отличается... но ломает ваше решение. я честно не понимаю почему. tx за вашу помощь - person user1161137; 16.08.2017
comment
это решение дает яблоко, бананы, грейпфрут, по умолчанию, арбуз... поэтому персики не отображаются, но по умолчанию отображаются. - person user1161137; 16.08.2017
comment
@user1161137 Первое перечисление работает, потому что Banane меньше по алфавиту, чем Default, но Peaches больше, чем Default, поэтому, когда вы пытаетесь проанализировать 1, Parse возвращает меньшее значение по имени . Для второго перечисления это Default - person George Alexandria; 16.08.2017
comment
@user1161137 user1161137 Если вы ищете решение для второго перечисления, вы можете попробовать обходной путь в ответе Sach. - person George Alexandria; 17.08.2017
comment
Да, второе перечисление - это то, с чем я имею дело. Я просто неправильно перевел проблему в стек. Фруктами не занимаюсь :-) - person user1161137; 17.08.2017