Extension method for adding value to bit field (flags enum)
Asked Answered
S

4

19

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?

Syreetasyria answered 26/4, 2011 at 16:38 Comment(0)
G
25

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);
Gnarled answered 26/4, 2011 at 16:43 Comment(5)
I can't have the first parameter passed by reference?Syreetasyria
Not in an extension method. You could create a standard utility method and do that though. You might be able to flip the method around have the one being added be the this parameter and the receiver be a ref parameter. MyFlags.Coke.AddTo(flags);Gnarled
Why can't you do it in an extension method?Syreetasyria
That's what the C# overlords decided :) I'm sure there are good technical reasons why not.Gnarled
Necro'ing Seems like this addition can be simplified by doing addTo |= add.Lorrianelorrie
N
17

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

Nihility answered 17/10, 2012 at 8:16 Comment(1)
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 (albeit refering to Javascript)Swatow
B
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();
Bondon answered 18/5, 2014 at 12:47 Comment(3)
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.Bandler
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: softwareengineering.stackexchange.com/questions/141175/…Bondon
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()Bandler
M
0

This works fine for me

public static void AddFlag(this ref EnumType current, EnumType toAdd)
{
     current |= toAdd;
}
Melnick answered 27/8, 2023 at 9:18 Comment(1)
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.Syreetasyria

© 2022 - 2025 — McMap. All rights reserved.