2013-08-09 10 views
5

Devo creare un SelectList da qualsiasi Enum nel mio progetto.Metodo di estensione Enum generico per selezione elenco

Ho il codice sotto il quale creo un elenco di selezione da un enum specifico, ma mi piacerebbe fare un metodo di estensione per QUALSIASI enum. Questo esempio viene recuperato il valore della DescriptionAttribute su ogni valore Enum

var list = new SelectList(
      Enum.GetValues(typeof(eChargeType)) 
      .Cast<eChargeType>() 
      .Select(n => new 
       { 
        id = (int)n, 
        label = n.ToString() 
       }), "id", "label", charge.type_id); 

Riferimento this post, come procedo?

public static void ToSelectList(this Enum e) 
{ 
    // code here 
} 

risposta

4

Quello che penso tu stia lottando, è il recupero della descrizione. Sono sicuro che una volta che hai quelle che è possibile definire il metodo finale che dà il risultato esatto.

Innanzitutto, se si definisce un metodo di estensione, funziona su un valore dell'enumerazione, non sul tipo di enum stesso. E penso che, per facilità di utilizzo, ti piacerebbe chiamare il metodo sul tipo (come un metodo statico). Sfortunatamente, non puoi definirli.

Quello che puoi fare è il seguente. Prima definire un metodo che recupera la descrizione del valore enum, se presente:

public static string GetDescription(this Enum value) { 
    string description = value.ToString(); 
    FieldInfo fieldInfo = value.GetType().GetField(description); 
    DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

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

successivo, definire un metodo che prende tutti i valori di un'enumerazione, e utilizzare il metodo precedente per cercare il valore che ci vuoi mostrare e restituire quella lista. L'argomento generico può essere dedotto.

public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>(this TEnum value) { 
    return Enum 
     .GetValues(typeof(TEnum)) 
     .Cast<TEnum>() 
     .Select(x => new KeyValuePair<TEnum, string>(x, ((Enum)((object)x)).GetDescription())) 
     .ToList(); 
} 

Infine, per facilità di utilizzo, un metodo per chiamarlo direttamente senza valore. Ma poi l'argomento generico non è facoltativo.

public static List<KeyValuePair<TEnum, string>> ToEnumDescriptionsList<TEnum>() { 
    return ToEnumDescriptionsList<TEnum>(default(TEnum)); 
} 

Ora possiamo usare in questo modo:

enum TestEnum { 
    [Description("My first value")] 
    Value1, 
    Value2, 
    [Description("Last one")] 
    Value99 
} 

var items = default(TestEnum).ToEnumDescriptionsList(); 
// or: TestEnum.Value1.ToEnumDescriptionsList(); 
// Alternative: EnumExtensions.ToEnumDescriptionsList<TestEnum>() 
foreach (var item in items) { 
    Console.WriteLine("{0} - {1}", item.Key, item.Value); 
} 
Console.ReadLine(); 

quali uscite:

Value1 - My first value 
Value2 - Value2 
Value99 - Last one 
+0

Grazie per la risposta dettagliata:) Per essere onesti, voglio solo qualcosa di veramente semplice (se possibile), così posso usare 'eChargeType.ToSelectList()' - Ho ridotto la complessità del mio esempio per escludere 'DescriptionAttribute' in quanto potrebbe aggiungere confusione inutile. Grazie! – Jimbo

+0

Purtroppo, 'eChargeType.ToSelectList()' non è possibile, dal momento che si desidera aggiungere un metodo statico a un tipo enum. E questo non è possibile, ma puoi creare un metodo di supporto statico da qualche parte. – Maarten

+0

Con riferimento al tuo commento sopra, puoi far luce su ciò che l'autore di questo post sperava di ottenere? http://stackoverflow.com/a/276589/175893 Avevo pensato che eravamo sulla stessa missione! Grazie – Jimbo

1

in ritardo alla festa, ma poiché non v'è alcuna risposta accettata e potrebbe aiutare gli altri:

Come menzionato @Maarten, un metodo di estensione funziona sul valore di un enum, non sul tipo enum, così come con soultion di Maarteen è possibile creare un valore fittizio o di default per chiamare il metodo di estensione su, tuttavia, si possono trovare, come ho fatto io, che è più semplice da usare solo un metodo di supporto statica in questo modo:

public static class EnumHelper 
{ 
    public static SelectList GetSelectList<T>(string selectedValue, bool useNumeric = false) 
    { 
     Type enumType = GetBaseType(typeof(T)); 

     if (enumType.IsEnum) 
     { 
      var list = new List<SelectListItem>(); 

      // Add empty option 
      list.Add(new SelectListItem { Value = string.Empty, Text = string.Empty }); 

      foreach (Enum e in Enum.GetValues(enumType)) 
      { 
       list.Add(new SelectListItem { Value = useNumeric ? Convert.ToInt32(e).ToString() : e.ToString(), Text = e.Description() }); 
      } 

      return new SelectList(list, "Value", "Text", selectedValue); 
     } 

     return null; 
    } 

    private static bool IsTypeNullable(Type type) 
    { 
     return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); 
    } 

    private static Type GetBaseType(Type type) 
    { 
     return IsTypeNullable(type) ? type.GetGenericArguments()[0] : type; 
    } 

È creerebbe l'elenco di selezione in questo modo:

viewModel.ProvinceSelect = EnumHelper.GetSelectList<Province>(model.Province); 

o utilizzando i valori numerici opzionali, invece di stringhe:

viewModel.MonthSelect = EnumHelper.GetSelectList<Month>(model.Month,true); 

l'idea di base per questo che ho ricevuto da here, anche se l'ho modificato in base alle mie esigenze. Una cosa che ho aggiunto è stata la possibilità di utilizzare facoltativamente int per il valore.Ho anche aggiunto un'estensione enum per ottenere l'attributo descrizione che si basa su this post del blog:

public static class EnumExtensions 
{ 
    public static string Description(this Enum en) 
    { 
     Type type = en.GetType(); 

     MemberInfo[] memInfo = type.GetMember(en.ToString()); 

     if (memInfo != null && memInfo.Length > 0) 
     { 
      object[] attrs = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false); 

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

     return en.ToString(); 
    }  
} 
0

Dal enum non può avere estensioni appuntato l'intera collezione un modo conveniente per estendere la classe base Enum è con un classe tipizzata statica. Questo permetterà di codice conciso come ad esempio:

Enum<MyCustomEnumType>.GetSelectItems(); 

che può essere raggiunto con il seguente codice:

public static class Enum<T> 
{ 
    public static SelectListItem[] GetSelectItems() 
    { 
     Type type = typeof(T); 
     return 
      Enum.GetValues(type) 
       .Cast<object>() 
       .Select(v => new SelectListItem() { Value = v.ToString(), Text = Enum.GetName(type, v) }) 
       .ToArray(); 
    } 
} 

Dal enum non hanno un tipo di interfaccia condivisa abuso è possibile, ma il nome della classe Enum dovrebbe dissipare ogni confusione.

0

Ecco un corretto [tipo pressofuso valore int] e semplificato [utilizza tostring sostituzione anziché getname] versione di Nathaniels risposta che restituisce un elenco invece di un array:

public static class Enum<T> 
{ 
    //usage: var lst = Enum<myenum>.GetSelectList(); 
    public static List<SelectListItem> GetSelectList() 
    { 
     return Enum.GetValues(typeof(T)) 
       .Cast<object>() 
       .Select(i => new SelectListItem() 
          { Value = ((int)i).ToString() 
           ,Text = i.ToString() }) 
       .ToList(); 
    } 

}