简体   繁体   English

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

[英]Extension method to convert Flags to IEnumerable<Enum> and conversely (C#)

I spent a couple hours trying to figure out a generic way of converting an Enum mask to an array of Enum values and, conversely, an array of Enum values to its Enum mask. 我花了几个小时试图找出一种将枚举掩码转换为枚举值数组的通用方法,相反,我将枚举值的数组转换为其枚举掩码。

Writing an extension method to do so was a bit of a pain so I just wanted to share my solution in case it could help someone. 编写扩展方法这样做有点痛苦所以我只是想分享我的解决方案,以防它可以帮助某人。 I'm sure it could be improved but, here it is! 我相信它可以改进,但是,它在这里!

The extension method below returns a mask from a list of Enum values. 下面的扩展方法从枚举值列表中返回一个掩码。

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

The extension method below returns a list of Enum values from a mask. 下面的扩展方法返回掩码中的枚举值列表。

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

Note that: 注意:

  1. Generic constraints in c# ( where T : ... ) cannot restrict T to an Enum c#中的通用约束( where T : ... )不能将T限制为枚举
  2. These methods do not check whether the Enum has the [Flags] attribute (could not figure that out) 这些方法不检查Enum是否具有[Flags]属性(无法弄清楚)

Usage: 用法:

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

To mask: 掩盖:

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

To values: 价值观:

TestEnum flags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
TestEnum[] array = flags.ToValues().ToArray();

TestEnum[] expectedArray = new[] { TestEnum.Plop, TestEnum.Foo };
CollectionAssert.AreEqual(expectedArray, array);

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM