Reputation: 178
I would like to use a flags enum as a filterset to filter on a single value enum.
When I use one flags enum to provide both, I have two objections:
The naming convention states than a flags enum is plural, and a single item enum not;
I would like the filter/flags enum to have values for "none" and "all", but these are not valid values when not used as a filter;
An example stating my intention (but which does not run properly due to type incompatibility between the two enums)
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))
...
As mentioned, this example does not do what I want. It feels not OK to only use the Materials enum because none and all are not valid values for an article finish.
I could use some casting to int to translate between both enums. But there should be a more elegant, non cluttered way to do this, right?
[edit after answer from Dennis] I actually did think about using a collection as a filter. Also it feels heavy weight, requires more code, while using enums is lightweight. However, when is doesn't do the job I have no user for it, lightweigt/elegant or not...
[edit after marking as ansered] Thank you all for your input!
Upvotes: 0
Views: 849
Reputation: 2258
The most optimal way is to use int
conversions rather than Enum.Parse
. To resolve your problem with HasFlag
you can create an extension method. Below is the code with test
[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
}
Upvotes: 1
Reputation: 787
You have a 2 solutions:
First:
Material value = (Material)Enum.Parse(typeof (Material), Materials.wood.ToString());
I.e. convert enums
Second: use only Materials enum. Not clear but simple.
Upvotes: 0
Reputation: 37800
IMO, using collection to hold the filter is much easier and readable, than manipulating flags:
// 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)))
{
// ...
}
Upvotes: 1