Is there a way to optionally force a [Flags]
enum to be "non-Flags" for specific uses?
For example, say I have
enum MyEnum {
X ,
Y ,
Z
}
Now let's say I have two classes A
and B
. Class B will mostly be used within an IEnumerable<B>
. Class A is responsible for parsing this list, but only when the enum matches a particular value;
class B {
MyEnum MyProperty { get; set; }
}
class A {
MyEnum Target = MyEnum.C;
void DoSomething(IEnumerable<B> list) {
for (var b in list) {
if (b.MyProperty == this.Target) {
// Do Some Work
}
}
}
}
Now suppose I want class A to be able to work with multiple types of B. I could add the [Flags] attribute to my enum and do something like this:
[Flags]
enum MyEnum {
None = 0,
X = 1,
Y = 2,
Z = 4
}
class B {
MyEnum MyProperty { get; set; }
}
class A {
MyEnum Target = MyEnum.X | MyEnum.Z;
void DoSomething(IEnumerable<B> list) {
for (var b in list) {
if (this.Target.HasFlag(b.MyProperty)) {
// Do Some Work
}
}
}
}
However, class B's MyProperty
can now be used as a flag, which is a problem because there's no such thing as a MyEnum.X | MyEnum.Y
in the context of B.MyProperty
. It makes sense within A
because I am targeting various kinds of class B.
The work around that I've come up with is this:
enum MyEnum {
None = 0,
X = 1,
Y = 2,
Z = 4
}
[Flags]
enum MyEnumTarget {
None = 0,
X = 1,
Y = 2,
Z = 4
}
class B {
MyEnum MyProperty { get; set; }
}
class A {
MyEnumTarget Target = MyEnumTarget.X | MyEnumTarget.Z;
void DoSomething(IEnumerable<B> list) {
for (var b in list) {
if (this.Target.HasFlag((MyEnumTarget)b.MyProperty)) {
// Do Some Work
}
}
}
}
While this works, it's definitely messy. I now have to keep track of two different enums. Any change I make in one, I have to make in the other and I have to make sure that the values are syncronized. On top of that I now have to cast to MyEnumTarget
to be able to pass the value to Enum.HasFlag
. Granted I could do bit-wise operations but then its not always so obvious what the intent is. Either way, I'd still need two "matching" enums.
Is there no better way to do to this? Is there some way to use a single enum type and force some sort of [NoFlags] attribute on B.MyProperty
. Or is having the two enums considered the best way / good practice?
I'm using C#6.0 if that matters
Fundamentally, each enum type either is designed to have be a bit mask, or isn't. Options you might consider:
A.Property
a List<MyEnum>
or similarB.Property
setter validate that only a single bit is set, throwing an ArgumentException
otherwiseSee more on this question at Stackoverflow