Extension method on enumeration, not instance of enumeration

30,791

Solution 1

Extension methods only work on instances, so it can't be done, but with some well-chosen class/method names and generics, you can produce a result that looks just as good:

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;
    }
}

Then you can get your select list like this:

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

IMO this reads a lot better than Things.ToSelectList().

Solution 2

No.

The best you can do is put it on a static class, like this:

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

Solution 3

Aaronaught's answer is really great, based on that I made the following implementation:

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.");
    }
}

In my opinion it's a little bit safer, as you can - almost - call it only with Enums, and of course instead of the throw you can simply return null if you want an exception-free version.

Solution 4

@Aaronaught has a very good answer. To extend his answer, you can also even make it more generic. I have this in a global library...

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

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

    return retVal;
}

Now you have de-coupled this functionality from the SelectList class. So you can call this in your SelectList methods, or anywhere else for that matter.

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");
    }
}

Solution 5

I use 'Type' instead of 'Enum' to add extension. Then I can get any type of list back from the method. Here it returns string values:

    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();
    }

Later I could use this syntax to get what I want:

var listOfThings = typeof (Things).AllDescription();
Share:
30,791

Related videos on Youtube

Jamezor
Author by

Jamezor

Updated on September 23, 2021

Comments

  • Jamezor
    Jamezor over 2 years

    I have an enumeration for my Things like so:

    public enum Things
    {
       OneThing,
       AnotherThing
    }
    

    I would like to write an extension method for this enumeration (similar to Prise's answer here) but while that method works on an instance of the enumeration, ala

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

    I would like it to work on the actual enumeration instead:

    var list = Things.ToSelectList();
    

    I could just do

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

    But I don't like the look of that :)

    I have gotten closer with the following extension method:

    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;
       }
    }
    

    Used like so:

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

    Can we do any better than that?

    • Iucounu
      Iucounu almost 11 years
      You can make a class that masquerades as an enum. The downsides are mostly non-standard programming, I guess, and the inability to get rid of the methods inherited from Object.
    • user3264784
      user3264784 about 10 years
      I don't think it is a right practice to use verb for names of classes. ideally class name should be noun and meaningful in itself.
  • spaceman
    spaceman over 12 years
    this is so brilliant i actually laughed out loud when i read it. i was so focused on making an enum to a selectlist i never thought of doing it the other way around.
  • undeniablyrob
    undeniablyrob over 12 years
    Another note is that you can use the where clause to improve your compiling on generic methods for enums... GetAllEnumValues<T>() where T : struct, IConvertible
  • Iucounu
    Iucounu almost 11 years
    You can make a class that masquerades as an enum. The downsides are mostly non-standard programming, I guess, and the inability to get rid of the methods inherited from Object.
  • Aaronaught
    Aaronaught almost 11 years
    @Iucounu: The downside is... it's not an enum. You don't get range checking, numeric representation, simple database storage, automatic string conversion, or any of the other benefits of an enum. Given those downsides and no real upside, I can't think of why you'd want to do it.
  • Iucounu
    Iucounu almost 11 years
    It provides the programming semantics of an enum with a static method, which making a good-looking method just doesn't do. I don't think you understood the code sample below; you certainly can have numeric representation and string conversion, nor is database storage a downside. It's at least a solution...
  • Aaronaught
    Aaronaught almost 11 years
    @Iucounu: I understood it perfectly well, it's the "typesafe enum" pattern from stone-age Java before the language designers finally wised up and implemented actual enums. Your solution isn't a solution because the question was about actual enums, and besides which, the comments to other answers are hardly the appropriate medium in which to be advertising your own.
  • InteXX
    InteXX almost 10 years
    New to C#, getting a compiler error at public static Of<T>(): "The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)". Can you assist?
  • Aaronaught
    Aaronaught almost 10 years
    @InteXX: Forgot a keyword. Updated.
  • InteXX
    InteXX almost 10 years
    Got it, thanks. This looks good, really looking forward to using it. Now I'm getting "'SelectList' does not contain a constructor that takes 3 arguments". Do you have a favorite constructor that you like to use with it?
  • Aaronaught
    Aaronaught almost 10 years
    @InteXX: This isn't a complete program, it's a code snippet. You can either write the rest of the constructors/methods yourself or reference the MVC class by namespace. If you're new to C# then I suggest attempting some more basic programs before applying concepts like this.
  • Igor Mironenko
    Igor Mironenko over 7 years
    The variable "type" GetValues(type) is not defined. If this code is partial or specific to MVC then please make it clear or even better, fix it so we don't have to learn anything else but C# to understand it
  • maembe
    maembe over 7 years
    I think you want to cast it as T rather than as Enum and return an IEnumerable<T>