获取任何枚举值的扩展方法

本文关键字:扩展 方法 任何 枚举 获取 | 更新日期: 2023-09-27 18:04:26

我一直在尝试创建一个扩展方法,可以在任何enum上工作,以返回其值。

而不是这样做:

Enum.GetValues(typeof(BiasCode)).Cast<BiasCode>()

这样做会很好:

new BiasCode().Values()

如果没有new会更好,但这是另一个问题。

我有一个。net提琴,有一个解决方案,这是接近(代码如下所示)。这段代码的问题是扩展方法返回List<int>。我想让它返回枚举值本身的列表。返回List<int>并不可怕;它只意味着我必须对结果进行强制转换。

这是可能的吗?我试图使扩展方法通用,但遇到了问题。这是我所能得到的最接近的:

using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
    public static void Main()
    {
        foreach (int biasCode in new BiasCode().Values())
        {
            DisplayEnum((BiasCode)biasCode);
        }
    }
    public static void DisplayEnum(BiasCode biasCode)
    {
        Console.WriteLine(biasCode);    
    }
}
public enum BiasCode
{
    Unknown,
    OC,
    MPP
}
public static class EnumExtensions
{
    public static List<int> Values(this Enum theEnum)
    {
        var enumValues = new List<int>();
        foreach (int enumValue in Enum.GetValues(theEnum.GetType()))
        {
            enumValues.Add(enumValue);
        }
        return enumValues;
    }
}

获取任何枚举值的扩展方法

您可以返回适当enum类型的实例(使用反射创建),但其静态类型不能为List<EnumType>。这将要求EnumType是该方法的泛型类型参数,但是该类型必须被约束为仅枚举类型,而这在c#中是不可能的。

然而,你可以在实践中足够接近(并添加运行时检查),所以你可以写一个这样工作的方法:

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

可以用

调用
var values = Values<BiasCode>();

我已经使该方法返回IEnumerable<TEnum>,而不是额外的LINQ-y风格的列表,但是您可以简单地返回一个返回值为.ToList()的真实列表。

你可以这样声明你的方法:

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

那么你可以叫它

Values<BiasCode>();

我想知道我是否错过了一些东西,因为所有的答案都使用通用方法作为解决方案的一部分。为什么不这样做呢?

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

小提琴在这里:https://dotnetfiddle.net/FRDuvD

这样,这个扩展方法将只对枚举可用。使用泛型方法,扩展方法似乎对所有类型都可用:

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

在编译时最好不要让Values()对字符串可用

这个怎么样

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

由于您正在寻找扩展方法,这里是:

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

编辑

我将把我的评论合并到Bob的回答中:

所以,我想我们都同意没有最好的解决方案,因为不可能在Enum类型上做where子句约束。另一个解决方案是使用以下方法签名(如Bob建议的):

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

对于这个解决方案,我们可以做得更好的是仅对Enum值进行约束。然而,与泛型解决方案相比,我们丢失了关于枚举类型的信息,我们在枚举类型上调用扩展方法。所以我们需要再铸一次。我看不出这和Bob在他的问题中最初发布的方法有多大区别,他返回List<int>并需要将其强制转换回我们的enum。

最优雅的解决方案可以通过使用带有静态检查的代码契约来实现。然而,它需要使用代码契约,如果只在这种情况下使用它们,可能会造成过度杀伤。使用代码契约使泛型为enum
类型

获取c#中任意枚举值的扩展方法

基于上面的解决方案,使用稍微不同的方法:

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

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

public enum Test
{
    First,
    Second,
    Third
}
[TestClass]
public class EnumTests
{
    [TestMethod]
    public void MyTestMethod()
    {
        var values = Enum<Test>.GetAll();
        Assert.AreEqual(3, values.Count());
    }
}
.net c#枚举扩展