将Flags转换为IEnumerable <enum>和相反(C#)</enum>的扩展方法

时间:2014-03-02 20:28:32

标签: c# enums extension-methods ienumerable

我花了几个小时试图找出将枚举掩码转换为枚举值数组的通用方法,相反,将Enum值数组转换为其枚举掩码。

编写扩展方法这样做有点痛苦所以我只是想分享我的解决方案,以防它可以帮助某人。我确定它可以改进,但是,这就是它!

2 个答案:

答案 0 :(得分:5)

下面的扩展方法从枚举值列表中返回一个掩码。

public static T ToMask<T>(this IEnumerable<T> values) where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be an enumerated type.");

     int builtValue = 0;
     foreach (T value in Enum.GetValues(typeof(T)))
     {
        if (values.Contains(value))
        {
            builtValue |= Convert.ToInt32(value);
        }
    }
    return (T)Enum.Parse(typeof(T), builtValue.ToString());
}

下面的扩展方法返回掩码中的枚举值列表。

public static IEnumerable<T> ToValues<T>(this T flags) where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be an enumerated type.");

    int inputInt = (int)(object)(T)flags;
    foreach (T value in Enum.GetValues(typeof(T)))
    {
        int valueInt = (int)(object)(T)value;
        if (0 != (valueInt & inputInt))
        {
            yield return value;
        }
    }
}

请注意:

  1. c#(where T : ...)中的通用约束不能将T限制为枚举
  2. 这些方法不会检查枚举是否具有[Flags]属性(无法弄清楚)
  3. 用法:

    [Flags]
    public enum TestEnum : int
    {
        None = 0,
        Plop = 1,
        Pouet = 2,
        Foo = 4,
        Bar = 8
    }
    

    掩盖:

    TestEnum[] enums = new[] { TestEnum.None, TestEnum.Plop, TestEnum.Foo };
    TestEnum flags = enums.ToMask();
    
    TestEnum expectedFlags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
    Assert.AreEqual(expectedFlags, flags);
    

    要价值观:

    TestEnum flags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
    TestEnum[] array = flags.ToValues().ToArray();
    
    TestEnum[] expectedArray = new[] { TestEnum.Plop, TestEnum.Foo };
    CollectionAssert.AreEqual(expectedArray, array);
    

答案 1 :(得分:4)

我需要一个简单的解决方案来转换相反的方向(而不是必须包含扩展名),所以这里有一个Linq解决方案将你的枚举的IEnumerable转换成一个标记的枚举:

MyEnum e = MyEnumList.Aggregate((MyEnum)0, (a,b) => a |= b);