web-dev-qa-db-fra.com

Méthode d'extension sur l'énumération, pas d'instance d'énumération

J'ai une énumération pour mes choses comme suit:

public enum Things
{
   OneThing,
   AnotherThing
}

Je voudrais écrire une méthode d'extension pour cette énumération (similaire à La réponse de Prise ici ) mais pendant que cette méthode fonctionne sur une instance de l'énumération, ala

Things thing; var list = thing.ToSelectList();

Je voudrais qu'il fonctionne sur le énumération réelle à la place:

var list = Things.ToSelectList();

Je pourrais juste faire 

var list = default(Things).ToSelectList();

Mais je n'aime pas le look de ça :) 

Je me suis rapproché avec la méthode d'extension suivante:

public static SelectList ToSelectList(this Type type)
{
   if (type.IsEnum)
   {
      var values = from Enum e in Enum.GetValues(type)
                   select new { ID = e, Name = e.ToString() };
      return new SelectList(values, "Id", "Name");
   }
   else
   {
      return null;
   }
}

Utilisé comme tel:

var list = typeof(Things).ToSelectList();

Peut-on faire mieux que ça?

43
Jamezor

Les méthodes d'extension ne fonctionnent que sur les instances, ce qui ne peut donc pas être fait, mais avec des noms de classe/méthode et des génériques bien choisis, vous pouvez produire un résultat aussi beau:

public class SelectList
{
    // Normal SelectList properties/methods go here

    public static SelectList Of<T>()
    {
        Type t = typeof(T);
        if (t.IsEnum)
        {
            var values = from Enum e in Enum.GetValues(type)
                         select new { ID = e, Name = e.ToString() };
            return new SelectList(values, "Id", "Name");
        }
        return null;
    }
}

Ensuite, vous pouvez obtenir votre liste de sélection comme ceci:

var list = SelectList.Of<Things>();

IMO cela se lit beaucoup mieux que Things.ToSelectList().

70
Aaronaught

Non.

Le mieux que vous puissiez faire est de le placer sur une classe statique, comme ceci:

public static class ThingsUtils { 
    public static SelectList ToSelectList() { ... }
}
5
SLaks

La réponse d'Aaronaught est vraiment géniale, basé sur le fait que j'ai réalisé l'implémentation suivante:

public class SelectList
{
    public static IEnumerable<Enum> Of<T>() where T : struct, IConvertible
    {
        Type t = typeof(T);
        if (t.IsEnum)
        {
            return Enum.GetValues(t).Cast<Enum>();
        }
        throw new ArgumentException("<T> must be an enumerated type.");
    }
}

À mon avis, c'est un peu plus sûr, car vous pouvez presque l'appeler uniquement avec Enums et bien sûr, au lieu du lancer, vous pouvez simplement renvoyer null si vous souhaitez une version sans exception.

4
qqbenq

@Aaronaught a une très bonne réponse. Pour étendre sa réponse, vous pouvez également la rendre plus générique. J'ai cela dans une bibliothèque mondiale ...

public static IQueryable GetAllEnumValues<T>()
{
    IQueryable retVal = null;

    Type targetType = typeof(T);
    if(targetType.IsEnum)
    {
        retVal = Enum.GetValues(targetType).AsQueryable();
    }

    return retVal;
}

Vous avez maintenant déconnecté cette fonctionnalité de la classe SelectList. Vous pouvez donc appeler cela dans vos méthodes SelectList ou ailleurs.

public class SelectList
{
    public static SelectList Of<T>
    {
        IQueryable enumValues = GetAllEnumValues<T>();
        var values = 
            from Enum e in enumValues
            select new { ID = e, Name = e.ToString() };
        return new SelectList(values, "Id", "Name");
    }
}
1
coderob

J'utilise 'Type' au lieu de 'Enum' pour ajouter une extension. Ensuite, je peux obtenir n'importe quel type de liste de la méthode. Ici, il retourne des valeurs de chaîne:

    public static string[] AllDescription(this Type enumType)
    {
        if (!enumType.IsEnum) return null;

        var list = new List<string>();
        var values = Enum.GetValues(enumType);

        foreach (var item in values)
        {
            // add any combination of information to list here:
            list.Add(string.Format("{0}", item));

            //this one gets the values from the [Description] Attribute that I usually use to fill drop downs
            //list.Add(((Enum) item).GetDescription());
        }

        return list.ToArray();
    }

Plus tard, je pourrais utiliser cette syntaxe pour obtenir ce que je veux:

var listOfThings = typeof (Things).AllDescription();
1
Bahram

À mon avis, c'est le moyen le plus propre. Pourquoi?

  • Cela fonctionne pour tout System.Enum
  • La méthode d'extension elle-même est plus propre.
  • Pour l'appeler, vous ajoutez simplement new et c'est un petit compromis (car il doit avoir une instance pour fonctionner.
  • Vous ne transmettez pas null et il ne compilera littéralement pas si vous essayez de l'utiliser avec un autre type.

Usage:

(new Things()).ToSelectList()

Méthode d'extension:

[Extension()]
public SelectList ToSelectList(System.Enum source)
{
    var values = from Enum e in Enum.GetValues(source.GetType)
                select new { ID = e, Name = e.ToString() };
    return new SelectList(values, "Id", "Name");    
}
0
toddmo