如何将整数标记为枚举的通用列表?

时间:2017-10-07 07:17:03

标签: c# generics enums enum-flags

我已经为我的问题寻找解决方案,但到目前为止我无法弄清楚如何做到这一点。

我需要获取由enum值标记的int值的列表。
我能够在特定情况下执行此操作,但我想为通用枚举器创建通用函数。

具体案例的代码是:

        IList<MyEnum> EnumList= new List<MyEnum>();
        MyEnum EnumIUseToFlag= (MyEnum)intToParse;

        foreach (MyEnumitem in Enum.GetValues(typeof(MyEnum)))
        {
            if (EnumIUseToFlag.HasFlag(item))
            {
                EnumList.Add(item);
            }
        }

现在,对于通用方法,我尝试的是:

    public static IList<T> GetFlaggedValues<T>(int intValue) where T : struct, IConvertible
    {

        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("T must be an enumerated type");
        }

        IList<T> listToReturn = new List<T>();
        Enum enumToParse = Enum.Parse(typeof(T), intValue.ToString()) as Enum;
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            // here I am not able to cast item in the integer
            //values i need to use in order to flag my enum

        }

        return listToReturn;
    }

3 个答案:

答案 0 :(得分:2)

简单的回答是 - 不要使用泛型。这个问题不需要。使用良好的旧继承并将标志作为System.Enum传递,这是所有枚举的基类。

public static IList<Enum> GetFlaggedValues(Enum flag) 
{
    return Enum
        .GetValues(flag.GetType())
        .Cast<Enum>()
        .Where(e => e.HasFlag(flag))
        .ToList();
}

这是一个简单的测试:

enum MyEnum
{
    Red = 0xF00,
    Orange = 0xFF0,
    Yellow = 0x0F0,
    Green = 0x0FF,
    Blue = 0x00F,
    Purple = 0xF0F
}

public static void Main()
{
    var list = GetFlaggedValues(MyEnum.Blue);
    foreach (var e in list)
    {
        Console.WriteLine(e);
    }
}

输出:

Blue
Green
Purple

由于我们使用Enum基类型的方式,不可能使用非枚举参数调用此方法,因此不需要进行混乱的验证检查并抛出异常。不能用c#中的泛型来做到这一点。

另一方面,回复类型为List<Enum>而不是List<MyEnum>可能会让您感到困扰。精细。如果你坚持使用结果集的强类型列表,你可以来回投射,如下所示:

public static IList<T> GetFlaggedValues<T>(T input) where T : struct, IConvertible
{
    Enum flag = input as Enum;
    if (flag == null) return new List<T>();
    return Enum
        .GetValues(typeof(T))
        .Cast<Enum>()
        .Where(e => e.HasFlag(flag))
        .Cast<T>()
        .ToList();
}

注意在最后一个例子中,如果输入实际上不是枚举,我只返回一个空列表,这似乎是合理的行为,因为它准确地反映了枚举中的哪些值匹配 - 没有一个。但如果您愿意,可以抛出异常。

另外,您可能已经注意到我更改了原型,以便您可以传递枚举本身而不是整数。这允许编译器推断类型,因此您只需调用

var list = GetFlaggedValues(MyEnum.Blue);

而不必输入

var list = GetFlaggedValues<MyEnum>((int)MyEnum.Blue);  //Ugly

如果你想传递一个整数,你总是可以投射它,如下所示:

var list = GetFlaggedValues((MyEnum)0xF0F);

...编译器会推断出<MyEnum>位。

DotNetFiddle

上的完整代码

答案 1 :(得分:0)

这对你有用:

    public static IList<T> GetFlaggedValues<T>(ulong intValue) where T : struct
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("T must be an enumerated type");
        }
        var flagAttrib = Attribute.GetCustomAttribute(typeof(T), typeof(FlagsAttribute));
        if(flagAttrib==null)
        {
            throw new ArgumentException("T must have [Flags] attribute.");
        }

        List<T> vals = new List<T>();
        foreach (var e in Enum.GetValues(typeof(T)))
        {
            var item = Convert.ToUInt64(e);
            if ((item & intValue) != 0)
                vals.Add((T)Enum.ToObject(typeof(T), item));
        }
        return vals;
    }

答案 2 :(得分:0)

在foreach中你可以添加下一行:

        var itemAsEnumValue = (Enum)Enum.Parse(typeof(T), item.ToString());

        if (enumToParse.HasFlag(itemAsEnumValue))
        {
            listToReturn.Add(item);
        }

Here is working .netfiddle example