17

Instead of doing this to add a value to flags enum variable:

MyFlags flags = MyFlags.Pepsi;
flags = flags | MyFlags.Coke;

I'd like to create an extension method to make this possible:

MyFlags flags = MyFlags.Pepsi;
flags.Add(MyFlags.Coke);

Possible? How do you do it?

Ronnie Overby
  • 45,287
  • 73
  • 267
  • 346

4 Answers4

24

Not in any useful way. Enums are value types, so when making an extension method a copy of the enum will get passed in. This means you need to return it in order to make use of it

    public static class FlagExtensions
    {
        public static MyFlags Add(this MyFlags me, MyFlags toAdd)
        {
             return me | toAdd;
        }
    }

    flags = flags.Add(MyFlags.Coke); // not gaining much here

And the other problem is you can't make this generic in any meaningful way. You'd have to create one extension method per enum type.

EDIT:

You can pull off a decent approximation by reversing the roles of the enums:

public static class FlagsExtensions
{
    public static void AddTo(this MyFlags add, ref MyFlags addTo)
    {
         addTo = addTo | add;
    }
}


MyFlags.Coke.AddTo(ref flags);
Matt Greer
  • 60,826
  • 17
  • 123
  • 123
16

I'm also working on Enum extension methods.

I tried to create add / remove generic methods for Enums, but I found it redundant.

To add you can just do:

MyFlags flags = MyFlags.Pepsi;
flags |= MyFlags.Coke;

To remove you can do:

MyFlags flags = MyFlags.Pepsi | MyFlags.Coke;
flags &= ~MyFlags.Coke;

Do not use XOR (^), it adds the flag if it does not exist.

flags ^= MyFlags.Coke; // Do not use!!!

Hope it helped. You can see more extension methods on: My blog

nawfal
  • 70,104
  • 56
  • 326
  • 368
Ofir
  • 2,174
  • 1
  • 16
  • 15
  • 2
    XOR actually toggles the flag -- so like you said it adds it if it didn't exist, but it should also remove it if it did exist. [A good reference](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators#Reverse_algorithm.3A_an_array_of_booleans_from_a_mask) (albeit refering to Javascript) – drzaus Jan 09 '13 at 15:43
2

Not a solution, but if your aim is to reduce verbosity and increase readability, a fluent interface with extension methods could help at least partially:

[Flags]
public enum MyFlags
{
    None = 0,
    A    = 0x1,
    B    = 0x2,
}

public static class MyFlagsExt
{
    public static MyFlags A(this MyFlags myFlags)
    {
        return myFlags | MyFlags.A;
    }

    public static MyFlags B(this MyFlags myFlags)
    {
        return myFlags | MyFlags.B;
    }
}

...

var flags = MyFlags.A.B();
Amir Abiri
  • 8,847
  • 11
  • 41
  • 57
  • 2
    Reducing verbosity shouldn't be anybody's aim in C#. It is compiled down to symbols, so file size of code doesn't matter. More Verbose ~= More Readable. On the same note, `MyFlags.A.B()` means nothing to me when I look at it. In order for me to understand this code, I have to understand the programmer (you) and the way your mind works. That isn't good for readability or maintainability. Also, nothing in this answer is an interface. So there is no fluid interface here, be that a contract or a UI. I can only agree with the first three words of your answer. – Suamere Jan 29 '18 at 19:20
  • 1
    There is no reason to downvote based on personal preference, just on how well or not the answer fits the question. Verbosity has nothing to do with file size. Experienced programmers know that too verbose code is harder to understand, as it reduces signal to noise ratio. If the OP wishes to reduce verbosity in this case, I trust his or her judgement. Also see here: https://softwareengineering.stackexchange.com/questions/141175/why-is-verbosity-bad-for-a-programming-language – Amir Abiri Jan 30 '18 at 14:50
  • ***1.*** The OP never said they want to reduce verbosity. ***2.*** Nothing I said was personal preference. ***3.*** That link you posted doesn't support your arguments as much as it says your answer is too cryptic. ***4.*** I'd also point out that my comment said More Verbose *About Equals* More Readable. E.G.: Walk the line between lengthy names and cryptic names, exactly as the link you posted mentions. It isn't obvious that `animal.Cat()` adds the Cat flag to the Animal. And how would it remove the cat flag? Also, your single-letter example is confusing `types.P().O().K().E().M().O().N()` – Suamere Jan 31 '18 at 16:46
0

This works fine for me

public static void AddFlag(this ref EnumType current, EnumType toAdd)
{
     current |= toAdd;
}
  • I suppose extension methods with value types passed by reference weren't an option back in 2011. These days, I wouldn't write functions that mutate their parameters. Thanks for sharing. – Ronnie Overby Aug 28 '23 at 14:31