【问题标题】:Extension method to convert Flags to IEnumerable<Enum> and conversely (C#)将标志转换为 IEnumerable<Enum> 的扩展方法,反之亦然(C#)
【发布时间】:2014-04-03 16:31:22
【问题描述】:

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

为此编写扩展方法有点痛苦,所以我只想分享我的解决方案,以防它对某人有所帮助。我敢肯定它可以改进,但是,就在这里!

【问题讨论】:

  • 为什么要将枚举掩码转换为枚举数组?你会用它做什么,你不能直接用面具做什么?
  • 天哪。为枚举编写扩展方法真的很烦人,不是吗?您可以将enums.Aggregate((x,y)=&gt;x|y); 作为一种非常快速的方法来进行枚举值以进行屏蔽,但是由于您需要包装它以处理转换等所有其他代码,因此将其放入扩展方法中会很痛苦。
  • 我的数据库包含掩码,但我的 REST API 公开了值列表。所以我需要一种方便的方式来回。我没想到总和,你说得很好!

标签: c# enums extension-methods ienumerable


【解决方案1】:

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

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. 这些方法不检查 Enum 是否具有 [Flags] 属性(无法确定)

用法:

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-28
      • 1970-01-01
      • 2010-11-03
      • 1970-01-01
      • 2011-08-15
      • 2010-12-03
      • 2011-10-08
      相关资源
      最近更新 更多