我想使用标志枚举作为过滤器集来过滤单个值枚举。
当我使用一个标志枚举来同时提供这两个标志时,我有两个反对意见:
-
命名约定规定标志枚举是复数,而单项枚举不是;
-
我希望过滤器/标志枚举具有"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());
即转换枚举
第二:仅使用"材质"枚举。不清楚但很简单。