It's 2021 and C# has a lot of nice features that mean there SHOULD be a much more elegant way of doing this. Let's discuss the claims of previous answers...
CLAIM 1:
Turning a flag off is inefficient because it uses two ops and invoking another method just adds more overhead.
THIS SHOULD BE FALSE.
If you add the AggressiveInlining compiler flag, the compiler SHOULD hoist the bitwise operation to a direct inline operation. If you are writing critical code, you may want to benchmark this to confirm since results can vary even between minor compiler versions. But the point is, you should be able to invoke a convenience method WITHOUT paying a method lookup cost.
CLAIM 2:
Its excessively verbose because you have to set the flag and then assign the return value.
THIS ALSO SHOULD BE FALSE. C# offers 'ref' which allows you to directly manipulate a value-type parameter by reference (in this case your enum). Combined with AggressiveInlining, the compiler should be smart enough to completely remove the ref pointers and the generated IL should look the same as if you directly inlined two bitwise operations.
CAVEATS:
Of course, this is all theory. Perhaps someone else can come along in the comments here and examine the IL from proposed code below. I don't have enough experience looking at IL myself (nor the time right now) to see if the hypothetical claims are true. But I figured this answer is still worth posting because the fact is that C# should be capable of doing what I'm explaining.
If someone else can confirm this, I can update the answer accordingly.
public enum MyCustomEnum : long
{
NO_FLAGS = 0,
SOME_FLAG = 1,
OTHER_FLAG = 1 << 1,
YET_ANOTHER_FLAG = 1 << 2,
ANOTHER STILL = 1 << 3
}
public static class MyCustomEnumExt
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void TurnOFF(ref this MyCustomEnum status, MyCustomEnum flag)
=> status &= ~flag;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void TurnON(ref this MyCustomEnum status, MyCustomEnum flag)
=> status |= flag;
}
You should be able to use the code like this:
//Notice you don't have to return a value from the extension methods to assign manually.
MyCustomEnum mc = MyCustomEnum.SOME_FLAG;
mc.TurnOFF(MyCustomEnum.SOME_FLAG);
mc.TurnON(MyCustomEnum.OTHER_FLAG);
Even if the compiler fails to optimize this correctly, it is still extremely handy. At the very least you can use it in non-critical code and expect excellent readability.
AddOneToInteger
method. – Linsang