Extension Method to Get the Values of Any Enum

十年热恋 提交于 2019-12-05 01:33:19
Jon

You can return an instance of the appropriate enum type (created using reflection), but its static type cannot be List<EnumType>. That would require EnumType to be a generic type parameter of the method, but then the type would have to be constrained to only enum types and that is not possible in C#.

However, you can get close enough in practice (and add runtime checks to top it off) so you can write a method that works like this:

public static IEnumerable<TEnum> Values<TEnum>()
where TEnum : struct,  IComparable, IFormattable, IConvertible
{
    var enumType = typeof(TEnum);

    // Optional runtime check for completeness    
    if(!enumType.IsEnum)
    {
        throw new ArgumentException();
    }

    return Enum.GetValues(enumType).Cast<TEnum>();
}

which you can invoke with

var values = Values<BiasCode>();

I have made the method return IEnumerable<TEnum> instead of a list for the extra LINQ-y flavor, but you can trivially return a real list with .ToList() on the return value.

You could declare your method like this:

public static List<T> Values<T>() where T : struct
{
    var type = typeof(T);

    if(!type.IsEnum) return null; // or throw exception

    return Enum.GetValues(type).Cast<T>().ToList();
}

Then you can call it

Values<BiasCode>();

I'm wondering if I'm missing something because all of the answers use a generic method as part of the solution. Why not just do something like this?

public static List<Enum> Values(this Enum theEnum)
{
    return Enum.GetValues(theEnum.GetType()).Cast<Enum>().ToList();
}

The fiddle is here: https://dotnetfiddle.net/FRDuvD

This way this extension method will only be available to enums. Using the generics approach, the extension method seems to be available to all types:

string someString = "x";
someString.Values();

It would be better not to have Values() available to a string at compile time.

How about this

class Program{
    static void Main(string[] args)
    {
        BiasCode b = BiasCode.MPP;
        var these = b.Values().ToList();
        //...  these contains the actual values as the enum type
    }
}
public static class EnumExtensions
{
    public static IEnumerable<T> Values<T>(this T theEnum) where T : struct,IComparable, IFormattable, IConvertible
    {
        var enumValues = new List<T>();

        if ( !(theEnum is Enum))
            throw new ArgumentException("must me an enum");

        return Enum.GetValues(typeof(T)).Cast<T>();
    }
}
Edin

Since you are looking for the extension method, here it is:

public static class EnumExtensions
{
   public static List<T> Values<T>(this T theEnum)
       where T : struct,  IComparable, IFormattable, IConvertible
   {
       if (!typeof(T).IsEnum) 
           throw new InvalidOperationException(string.Format("Type {0} is not enum.", typeof(T).FullName)); 

       return Enum.GetValues(theEnum.GetType()).Cast<T>().ToList();
   }
}

EDIT

I will incorporate my comment in Bob's answer here:

So, I think we could all agree that there is no best solution for this, since it is not possible to do a where clause constraint on Enum type. Another solution would be to have a following method signature (as Bob suggested):

public static List<Enum> Values(this Enum theEnum)

What we would do better with this solution is the constraint only on Enum values. However, in comparison to the generic solution, we lose the information about the enum type, on which we are invoking your extension method. So we need to cast it again. And I do not see much difference between this and the approach originally posted in by Bob in his question, where he returns List<int> and needs to cast it back to our enum.

The most elegant solution can be achieved by using Code Contracts with static checking. However it requires usage of the code contracts and it would probably an overkill if they are to be used in this single case. This approach was addressed in the following thread: Using code contracts to make a generic to be of type enum

Extension method to get the values of any enum in C#

Based on solutions above with slightly different approach:

public static class Enum<TEnum> where TEnum : struct, IComparable, IFormattable, IConvertible
{
    public static IEnumerable<TEnum> GetAll()
    {
        var t = typeof(TEnum);
        if (!t.IsEnum)
            throw new ArgumentException();

        return Enum.GetValues(t).Cast<TEnum>();
    }
}

Usage

var values = Enum<MyEnum>.GetAll();

Test

public enum Test
{
    First,
    Second,
    Third
}

[TestClass]
public class EnumTests
{
    [TestMethod]
    public void MyTestMethod()
    {
        var values = Enum<Test>.GetAll();
        Assert.AreEqual(3, values.Count());
    }
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!