C#将单值枚举与标志枚举相结合



我想使用标志枚举作为过滤器集来过滤单个值枚举。

当我使用一个标志枚举来同时提供这两个标志时,我有两个反对意见:

  • 命名约定规定标志枚举是复数,而单项枚举不是;

  • 我希望过滤器/标志枚举具有"none"one_answers"all"的值,但当不用作过滤器时,这些值是无效的;

一个示例说明了我的意图(但由于两个枚举之间的类型不兼容而无法正常运行)

    enum Material
    {
        wood,
        metal,
        plastic
    }
    [Flags]
    enum Materials
    {
        none = 0,
        wood = 1,
        metal = 2,
        plastic = 4,
        all = 7
    }
    var filter = Materials.all;
    foreach (article in articles.Where(a => Filter.HasFlag(a.FinishMaterial))
        ...

如前所述,这个例子并没有达到我想要的效果。只使用Materials枚举感觉不太好,因为none和all都不是文章结束的有效值。

我可以使用一些对int的强制转换来在两个枚举之间进行转换。但应该有一种更优雅、不杂乱的方式来做到这一点,对吧?

[根据Dennis的回答进行编辑]实际上,我确实考虑过使用集合作为过滤器。而且它感觉很重,需要更多的代码,而使用枚举是轻量级的。然而,当它不起作用时,我没有用户,无论它是否优雅。。。

[标记为ansered后编辑]感谢大家的投入!

最理想的方法是使用int转换而不是Enum.Parse。要解决HasFlag的问题,可以创建一个扩展方法。以下是测试的代码

[TestClass]
public class MaterialsTests
{
    [TestMethod]
    public void Contains_wroks_as_expected()
    {
        var filter = Materials.all;
        Assert.IsTrue(filter.Contains(Material.metal));
    }
}
public static class Extensions
{
    public static bool Contains(this Materials filter, Material material)
    {
        var valueToFilter = (Materials)(int)(material);
        return filter.HasFlag(valueToFilter);
    }
}
public enum Material
{
    wood = 1,
    metal = 2,
    plastic = 4
}
[Flags]
public enum Materials
{
    none = 0,
    wood = 1,
    metal = 2,
    plastic = 4,
    all = 7
}

IMO,使用集合来保存过滤器比操作标志更容易阅读:

// This is equivalent of "var filter = Materials.all";
// an empty collection is equivalent of "Materials.None"
var filter = (Material[])Enum.GetValues(typeof(Material));
// use next line, if you need to modify the filter:
// var filter = ((Material[])Enum.GetValues(typeof(Material))).ToList();
foreach (article in articles.Where(a => filter.Contains(a.FinishMaterial)))
{
    // ...
}

您有两个解决方案:

第一:

Material value = (Material)Enum.Parse(typeof (Material), Materials.wood.ToString());

即转换枚举

第二:仅使用"材质"枚举。不清楚但很简单。

最新更新