Enum с целыми строками

У меня есть общедоступный enum, например:

public enum occupancyTimeline
{
    TwelveMonths,
    FourteenMonths,
    SixteenMonths,
    EighteenMonths
}

который я буду использовать для меню DropDown, например:

@Html.DropDownListFor(model => model.occupancyTimeline, 
   new SelectList(Enum.GetValues(typeof(CentralParkLCPreview.Models.occupancyTimeline))), "")

Теперь я ищу, чтобы мои ценности были такими, как

12 месяцев, 14 месяцев, 16 месяцев, 18 месяцев вместо TweleveMonths, FourteenMonths, SixteenMonths, EighteenMonths

Как бы это сделать?

Ответ 1

Вы можете проверить эту ссылку

его решение предназначалось для Asp.NET, но благодаря простой модификации вы можете использовать его в MVC, например

/// <span class="code-SummaryComment"><summary></span>
/// Provides a description for an enumerated type.
/// <span class="code-SummaryComment"></summary></span>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field, 
 AllowMultiple = false)]
public sealed class EnumDescriptionAttribute :  Attribute
{
   private string description;

   /// <span class="code-SummaryComment"><summary></span>
   /// Gets the description stored in this attribute.
   /// <span class="code-SummaryComment"></summary></span>
   /// <span class="code-SummaryComment"><value>The description stored in the attribute.</value></span>
   public string Description
   {
      get
      {
         return this.description;
      }
   }

   /// <span class="code-SummaryComment"><summary></span>
   /// Initializes a new instance of the
   /// <span class="code-SummaryComment"><see cref="EnumDescriptionAttribute"/> class.</span>
   /// <span class="code-SummaryComment"></summary></span>
   /// <span class="code-SummaryComment"><param name="description">The description to store in this attribute.</span>
   /// <span class="code-SummaryComment"></param></span>
   public EnumDescriptionAttribute(string description)
       : base()
   {
       this.description = description;
   }
}

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

/// <span class="code-SummaryComment"><summary></span>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// <span class="code-SummaryComment"></summary></span>
public static class EnumHelper
{
   /// <span class="code-SummaryComment"><summary></span>
   /// Gets the <span class="code-SummaryComment"><see cref="DescriptionAttribute" /> of an <see cref="Enum" /></span>
   /// type value.
   /// <span class="code-SummaryComment"></summary></span>
   /// <span class="code-SummaryComment"><param name="value">The <see cref="Enum" /> type value.</param></span>
   /// <span class="code-SummaryComment"><returns>A string containing the text of the</span>
   /// <span class="code-SummaryComment"><see cref="DescriptionAttribute"/>.</returns></span>
   public static string GetDescription(Enum value)
   {
      if (value == null)
      {
         throw new ArgumentNullException("value");
      }

      string description = value.ToString();
      FieldInfo fieldInfo = value.GetType().GetField(description);
      EnumDescriptionAttribute[] attributes =
         (EnumDescriptionAttribute[])
       fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);

      if (attributes != null && attributes.Length > 0)
      {
         description = attributes[0].Description;
      }
      return description;
   }

   /// <span class="code-SummaryComment"><summary></span>
   /// Converts the <span class="code-SummaryComment"><see cref="Enum" /> type to an <see cref="IList" /> </span>
   /// compatible object.
   /// <span class="code-SummaryComment"></summary></span>
   /// <span class="code-SummaryComment"><param name="type">The <see cref="Enum"/> type.</param></span>
   /// <span class="code-SummaryComment"><returns>An <see cref="IList"/> containing the enumerated</span>
   /// type value and description.<span class="code-SummaryComment"></returns></span>
   public static IList ToList(Type type)
   {
      if (type == null)
      {
         throw new ArgumentNullException("type");
      }

      ArrayList list = new ArrayList();
      Array enumValues = Enum.GetValues(type);

      foreach (Enum value in enumValues)
      {
         list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
      }

      return list;
   }
}

тогда вы украшаете свое перечисление как

public enum occupancyTimeline
{
    [EnumDescriptionAttribute ("12 months")]
    TwelveMonths,
    [EnumDescriptionAttribute ("14 months")]
    FourteenMonths,
    [EnumDescriptionAttribute ("16 months")]
    SixteenMonths,
    [EnumDescriptionAttribute ("18 months")]
    EighteenMonths
}

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

ViewBag.occupancyTimeline =new SelectList( EnumHelper.ToList(typeof(occupancyTimeline)),"Value","Key");

и, на ваш взгляд, вы можете использовать следующие

@Html.DropdownList("occupancyTimeline")

надеюсь, что это поможет вам

Ответ 2

Я сделал себе метод расширения, который я теперь использую в каждом проекте:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.Mvc;

namespace App.Extensions
{
    public static class EnumExtensions
    {
        public static SelectList ToSelectList(Type enumType)
        {
            return new SelectList(ToSelectListItems(enumType));
        }

        public static List<SelectListItem> ToSelectListItems(Type enumType, Func<object, bool> itemSelectedAction = null)
        {
            var arr = Enum.GetValues(enumType);
            return (from object item in arr
                    select new SelectListItem
                    {
                        Text = ((Enum)item).GetDescriptionEx(typeof(MyResources)),
                        Value = ((int)item).ToString(),
                        Selected = itemSelectedAction != null && itemSelectedAction(item)
                    }).ToList();
        }

        public static string GetDescriptionEx(this Enum @this)
        {
            return GetDescriptionEx(@this, null);
        }

        public static string GetDescriptionEx(this Enum @this, Type resObjectType)
        {
            // If no DescriptionAttribute is present, set string with following name
            // "Enum_<EnumType>_<EnumValue>" to be the default value.
            // Could also make some code to load value from resource.

            var defaultResult = $"Enum_{@this.GetType().Name}_{@this}";

            var fi = @this.GetType().GetField(@this.ToString());
            if (fi == null)
                return defaultResult;

            var customAttributes = fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (customAttributes.Length <= 0 || customAttributes.IsNot<DescriptionAttribute[]>())
            {
                if (resObjectType == null)
                    return defaultResult;

                var res = GetFromResource(defaultResult, resObjectType);
                return res ?? defaultResult;
            }

            var attributes = (DescriptionAttribute[])customAttributes;
            var result = attributes.Length > 0 ? attributes[0].Description : defaultResult;
            return result ?? defaultResult;
        }

        public static string GetFromResource(string defaultResult, Type resObjectType)
        {
            var searchingPropName = defaultResult;
            var props = resObjectType.GetProperties();
            var prop = props.FirstOrDefault(t => t.Name.Equals(searchingPropName, StringComparison.InvariantCultureIgnoreCase));
            if (prop == null)
                return defaultResult;
            var res = prop.GetValue(resObjectType) as string;
            return res;
        }

        public static bool IsNot<T>(this object @this)
        {
            return !(@this is T);
        }
    }
}

И затем используйте его как это (например, в View.cshtml) (код для разбиения на две строки для ясности, также может сделать oneliner):

// A SelectList without default value selected
var list1 = EnumExtensions.ToSelectListItems(typeof(occupancyTimeline));
@Html.DropDownListFor(model => model.occupancyTimeline, new SelectList(list1), "")

// A SelectList with default value selected if equals "DesiredValue"
// Selection is determined by lambda expression as a second parameter to
// ToSelectListItems method which returns bool.
var list2 = EnumExtensions.ToSelectListItems(typeof(occupancyTimeline), item => (occupancyTimeline)item == occupancyTimeline.DesiredValue));
@Html.DropDownListFor(model => model.occupancyTimeline, new SelectList(list2), "")

Обновление

Основываясь на предположении Фила, я обновил выше код с возможностью считывать значение отображения enum с некоторого ресурса (если есть). Имя элемента в ресурсе должно быть в форме Enum_<EnumType>_<EnumValue> (например, Enum_occupancyTimeline_TwelveMonths). Таким образом вы можете предоставить текст для значений enum в файле ресурсов, не украсив ваши значения перечисления некоторыми атрибутами. Тип ресурса (MyResource) включен непосредственно в метод ToSelectItems. Вы можете извлечь его как параметр метода расширения.

Другим способом присвоения имен значениям перечисления является атрибут Description (это работает без адаптации кода к изменениям, которые я сделал). Например:

public enum occupancyTimeline
{
    [Description("12 Months")]
    TwelveMonths,
    [Description("14 Months")]
    FourteenMonths,
    [Description("16 Months")]
    SixteenMonths,
    [Description("18 Months")]
    EighteenMonths
}

Ответ 3

Сделать расширение Описание для перечисления

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.ComponentModel;
public static class EnumerationExtensions
{
//This procedure gets the <Description> attribute of an enum constant, if any.
//Otherwise, it gets the string name of then enum member.
[Extension()]
public static string Description(Enum EnumConstant)
{
    Reflection.FieldInfo fi = EnumConstant.GetType().GetField(EnumConstant.ToString());
    DescriptionAttribute[] attr = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
    if (attr.Length > 0) {
        return attr(0).Description;
    } else {
        return EnumConstant.ToString();
    }
}

}

Ответ 4

Вы можете использовать EnumDropDownListFor для этой цели. Вот пример того, что вы хотите. (Просто не забудьте использовать EnumDropDownListFor, вы должны использовать ASP MVC 5 и Visual Studio 2015.):

Ваш вид:

@using System.Web.Mvc.Html
@using WebApplication2.Models
@model WebApplication2.Models.MyClass

@{
    ViewBag.Title = "Index";
}

@Html.EnumDropDownListFor(model => model.occupancyTimeline)

И ваша модель:

public enum occupancyTimeline
{
    [Display(Name = "12 months")]
    TwelveMonths,
    [Display(Name = "14 months")]
    FourteenMonths,
    [Display(Name = "16 months")]
    SixteenMonths,
    [Display(Name = "18 months")]
    EighteenMonths
}

Ссылка: Что нового в ASP.NET MVC 5.1

Ответ 5

public namespace WebApplication16.Controllers{

    public enum occupancyTimeline:int {
        TwelveMonths=12,
        FourteenMonths=14,
        SixteenMonths=16,
        EighteenMonths=18
    }

    public static class MyExtensions {
        public static SelectList ToSelectList(this string enumObj)
        {
            var values = from occupancyTimeline e in Enum.GetValues(typeof(occupancyTimeline))
                         select new { Id = e, Name = string.Format("{0} Months",Convert.ToInt32(e)) };
            return new SelectList(values, "Id", "Name", enumObj);
        }
    }

}

Использование

@using WebApplication16.Controllers
@Html.DropDownListFor(model => model.occupancyTimeline,Model.occupancyTimeline.ToSelectList());

Ответ 6

public enum occupancyTimeline
{
    TwelveMonths=0,
    FourteenMonths=1,
    SixteenMonths=2,
    EighteenMonths=3
}
public string[] enumString = {
    "12 Months", "14 Months", "16 Months", "18 Months"};

string selectedEnum = enumString[(int)occupancyTimeLine.TwelveMonths];

или

public enum occupancyTimeline
{
    TwelveMonths,
    FourteenMonths,
    SixteenMonths,
    EighteenMonths
}
public string[] enumString = {
    "12 Months", "14 Months", "16 Months", "18 Months"};


string selectedEnum = enumString[DropDownList.SelectedIndex];

Ответ 7

В дополнение к использованию атрибута для описания (см. другие ответы или использование Google), я часто использую файлы RESX, где ключ представляет собой текст перечисления (например, TwelveMonths), а значение - желаемый текст.

Тогда относительно тривиально выполнять функцию, которая возвращает желаемый текст, а также легко переводить значения для многоязычных приложений.

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

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

Обычно у меня есть один класс для получения значений (отображаемое имя) для типа enum, которые необходимо отобразить, и одного файла unit test для каждого файла ресурсов, хотя у меня есть некоторые другие классы для некоторого общего кода, например, для сравнения ключа в файл ресурса со значением в enum для unit test (и одна перегрузка позволяет указать исключение).

Кстати, в таком случае имеет смысл иметь значение enum, соответствующее числу месяцев (например, TwelveMonths = 12). В этом случае вы также можете использовать string.Format для отображаемых значений, а также иметь исключения в ресурсе (например, сингулярные).

Ответ 9

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

Определить общий EnumHelper для формирования перечислений:

public abstract class EnumHelper<T> where T : struct
{
    static T[] _valuesCache = (T[])Enum.GetValues(typeof(T));

    public virtual string GetEnumName()
    {
        return GetType().Name;
    }

    public static T[] GetValuesS()
    {
        return _valuesCache;
    }

    public T[] GetValues()
    {
        return _valuesCache;
    }      

    virtual public string EnumToString(T value)
    {
        return value.ToString();
    }                
}

Определите вспомогательный помощник расширения раскрывающегося списка MVC:

public static class SystemExt
{
    public static MvcHtmlString DropDownListT<T>(this HtmlHelper htmlHelper,
        string name,
        EnumHelper<T> enumHelper,
        string value = null,
        string nonSelected = null,
        IDictionary<string, object> htmlAttributes = null)
        where T : struct
    {
        List<SelectListItem> items = new List<SelectListItem>();

        if (nonSelected != null)
        {
            items.Add(new SelectListItem()
            {
                Text = nonSelected,
                Selected = string.IsNullOrEmpty(value),
            });
        }

        foreach (T item in enumHelper.GetValues())
        {
            if (enumHelper.EnumToIndex(item) >= 0)
                items.Add(new SelectListItem()
                {
                    Text = enumHelper.EnumToString(item),
                    Value = item.ToString(),                 //enumHelper.Unbox(item).ToString()
                    Selected = value == item.ToString(),
                });
        }

        return htmlHelper.DropDownList(name, items, htmlAttributes);
    }
}

Каждый раз, когда вам нужно форматировать некоторые Enums, определите EnumHelper для конкретного перечисления T:

public class OccupancyTimelineHelper : EnumHelper<OccupancyTimeline>
{
    public override string EnumToString(occupancyTimeline value)
    {
        switch (value)
        {
            case OccupancyTimelineHelper.TwelveMonths:
                return "12 Month";
            case OccupancyTimelineHelper.FourteenMonths:
                return "14 Month";
            case OccupancyTimelineHelper.SixteenMonths:
                return "16 Month";
            case OccupancyTimelineHelper.EighteenMonths:
                return "18 Month";
            default:
                return base.EnumToString(value);
        }
    }
}

Наконец, используйте код в представлении:

@Html.DropDownListT("occupancyTimeline", new OccupancyTimelineHelper())

Ответ 10

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

public static List<int> PermittedMonths = new List<int>{12, 14, 16, 18};

Тогда просто:

foreach(var permittedMonth in PermittedMonths)
{
    MyDropDownList.Items.Add(permittedMonth.ToString(), permittedMonth + " months");
}

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