Получить описание значения Enum ‹T›

У меня есть класс enumHelper, который содержит:

public static IList<T> GetValues()
{
  IList<T> list = new List<T>();
  foreach (object value in Enum.GetValues(typeof(T)))
  {
    list.Add((T)value);
  }
  return list;
}

и

public static string Description(Enum value)
{
  Attribute DescAttribute = LMIGHelper.GetAttribute(value, typeof(DescriptionAttribute));
  if (DescAttribute == null)
    return value.ToString();
  else
    return ((DescriptionAttribute)DescAttribute).Description;
}

мое перечисление выглядит примерно так:

public enum OutputType
{
    File,
    [Description("Data Table")]
    DataTable
}

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

BindingList<KeyValuePair<OutputType, string>> list = Enum<OutputType>.GetBindableList();
cbo.datasource=list;
cbo.DisplayMember="Value";
cbo.ValueMember="Key";

Для этого я добавил:

public static BindingList<KeyValuePair<T, string>> GetBindingList()
{
    BindingList<KeyValuePair<T, string>> list = new BindingList<KeyValuePair<T, string>>();
    foreach (T value in Enum<T>.GetValues())
    {
        string Desc = Enum<T>.Description(value);
        list.Add(new KeyValuePair<T, string>(value, Desc));
    }
    return list;
}

Но «Enum.Description (значение)» даже не компилируется: аргумент '1': невозможно преобразовать из 'T' в 'System.Enum'

Как я могу это сделать? Это вообще возможно?

Спасибо.


person Community    schedule 17.11.2008    source источник
comment
Ваш метод описания должен быть методом расширения? Если да, то вы пропустили это ключевое слово.   -  person Jeff Yates    schedule 19.11.2008
comment
См. Мой ответ на этот вопрос stackoverflow.com/questions/6145888/   -  person Nick    schedule 20.04.2016


Ответы (3)


Прочтите эту статью. Вы можете сделать это, используя атрибут System.ComponentModel.DescriptionAttribute или создав свой собственный атрибут:

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

   /// <summary>
   /// Gets the description stored in this attribute.
   /// </summary>
   /// <value>The description stored in the attribute.</value>
   public string Description
   {
      get
      {
         return this.description;
      }
   }

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

Затем вам нужно украсить значения перечисления этим новым атрибутом:

public enum SimpleEnum
{
   [EnumDescription("Today")]
   Today,

   [EnumDescription("Last 7 days")]
   Last7,

   [EnumDescription("Last 14 days")]
   Last14,

   [EnumDescription("Last 30 days")]
   Last30,

   [EnumDescription("All")]
   All
} 

Вся «магия» происходит в следующих методах расширения:

/// <summary>
/// Provides a static utility object of methods and properties to interact
/// with enumerated types.
/// </summary>
public static class EnumHelper
{
   /// <summary>
   /// Gets the <see cref="DescriptionAttribute" /> of an <see cref="Enum" /> 
   /// type value.
   /// </summary>
   /// <param name="value">The <see cref="Enum" /> type value.</param>
   /// <returns>A string containing the text of the
   /// <see cref="DescriptionAttribute"/>.</returns>
   public static string GetDescription(this 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;
   }

   /// <summary>
   /// Converts the <see cref="Enum" /> type to an <see cref="IList" /> 
   /// compatible object.
   /// </summary>
   /// <param name="type">The <see cref="Enum"/> type.</param>
   /// <returns>An <see cref="IList"/> containing the enumerated
   /// type value and description.</returns>
   public static IList ToList(this 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;
   }
} 

Наконец, вы можете просто привязать поле со списком:

combo.DataSource = typeof(SimpleEnum).ToList();
person Scott Dorman    schedule 06.01.2009
comment
Оооо, вы могли бы написать это в своем ответе. - person Henrik; 01.03.2011
comment
Есть ли какая-то конкретная причина использовать здесь ArrayList? Разве List ‹T› был бы лучше? - person nawfal; 10.06.2013
comment
@Scott Спасибо за ваш код. Если мы хотим вернуть значение int вместо перечисления в списке. мы можем использовать Convert.toInt (значение). ref: stackoverflow.com/questions/908543/ надеюсь, что это кому-то поможет. - person Ram; 02.02.2014

Вам следует изменить:

public static string Description(Enum value)
{
  ...
}

to

public static string Description(T value)
{
   ...
}

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

На самом деле вам нужно поразмыслить над полями перечисления и сравнить значение каждого с заданным вами значением (результаты должны быть кэшированы для повышения производительности):

foreach(var field in typeof(T).GetFields())
{
    T fieldValue;

    try
    {
        fieldValue = (T) field.GetRawConstantValue();
    }
    catch(InvalidOperationException)
    {
        // For some reason, one of the fields returned is {Int32 value__},
        // which throws an InvalidOperationException if you try and retrieve
        // its constant value.
        //
        // I am unsure how to check for this state before
        // attempting GetRawConstantValue().

        continue;
    }

    if(fieldValue == value)
    {
        var attribute = LMIGHelper.GetAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;

        return attribute == null ? value.ToString() : attribute.Description;
    }
}

Измените ответ на следующий вопрос

В методе FillComboFromEnum отсутствует параметр типа для перечисления. Попробуй это:

public static void FillComboFromEnum<T>(ComboBox Cbo, BindingList<KeyValuePair<T, string>> List) where T : struct

Обратите внимание, что я ограничил тип структурой. Это не ограничение полного перечисления, но оно ближе, чем ничего.

person Bryan Watts    schedule 17.11.2008

Enum не имеет метода Description (). Лучшее, что вы могли бы сделать, - это реализовать в вашем перечислении интерфейс с методом Description (). Если вы сделаете это, тогда вы сможете

public static BindingList<KeyValuePair<T extends _interface_, String>> getBindingList()

а затем внутри этого вы можете ссылаться на

T foo = ...?
foo.Description(...);
person nsayer    schedule 17.11.2008