Bit fields

I'm trying to write a general method that can set a flag on an arbitrary bit field. Something like this


public static void SetFlag(Enum flags, Enum flag)
{
    flags = flags | flag;//This won't work!!
}

So that when I write the following it will show "A, B"


[Flags]
enum Test {A = 1, B = 2, C = 4};

private void TestSetFlag()
{
    Test test;
    SetFlag(test, Test.A);
    SetFlag(test, Test.B);
    MessageBox.Show(test.ToString());
}

How do I write my SetFlag method

Thanks, Brian


Answer this question

Bit fields

  • zeecue

    It don't - sorry... 

    The problem is that the operator '|' can't be applied to operands of type System.Enum.

    I have also tried converting the enums to int like this


    public static void SetFlag(ref Enum flags, Enum flag)
    {
        flags = Convert.ToInt32(flags) | Convert.ToInt32(flag);//This won't work either!!
    }

    but then I can't convert it back to an enum !!

    Can't this be done in some way

  • mimminito

    yes, but there you complained that.

    SetFlag(ref (int)test, (int)Test.A);

    gave a correct compile error, this should be

    SetFlag(ref test, (int)Test.A);

    there are many ways to do simple things!
    As said if you want true Generics you'll have to wait a while!

  • Marcin2k

    try:

    public static void SetFlag(ref int flags, Test flag)
    {
        flags |= flag;
    }

    ...
    enum Test {A = 1, B = 2, C = 4};
    int test = 0;

    SetFlag(ref test, Test.A);
    SetFlag(ref test, A);  // compiler should figure Test.A is meant here
    ...

    As the compiler says "a ref argument must be an lvalue". 
    ref simply means a reference to a variable,  as said a 'Test' can only hold a 'Test'
    and not the sum of 'Test's.
    You might try AB = A|B then perhaps A and B might be |'rd into AB (I haven't tested that)
    Something like "ref (sometype)var" is always out of the question, it makes no sense what soever or say differently is nonsense (hi hi)
    same thing with "out"-parameters, casting in cals is nonsense.
    The second parameter of course can be an int, in this case the cast in the call might be automatic.
    hope this helps.

  • Karim Hemani


    public static void SetFlag(Enum flags, Enum flag)
    {
        flags = flags | flag;//This won't work!!
    }

    this won't work because flags is a value parameter

    public static void SetFlag(<strong>ref</strong> Enum flags, Enum flag)
    {
        flags = flags | flag;
    }

    should work



  • Isuru

    Isn't this what I did earlier (see post nr. 5)
  • BCullenward88

    Thanks for your time Aale!

    I tried changing the flags to an int like this and it compiles ok


    public static void SetFlag(ref int flags, int flag)
    {
        flags = flags | flag;
    }

    But when I try to write this


    [Flags]
    enum Test {A = 1, B = 2, C = 4};

    Test test = 0;

    SetFlag(ref (int)test, (int)Test.A);

    the compiler says that "a ref argument must be an lvalue".

    Any other ideas


  • DeJohn P

    I guess I'll have to wait then - thanks for your help!
  • arif_setiawan

    Oops, stupid me. Your  flags you defined as an Enum, so can only hold an Enum,  if you redefine it as an int it ought to work. An Enum can only hold an Enum, and not a combination of Enums. Those convert statements are not needed I think since your Enums are mapped onto integers.

    A quick look through the help shows me that: <strong>c# does not support bitfields</strong>
    Under the Keyword Enumerations .Net framework
    C# sample shows: (only lifted the relevant part)

    // A bit field or flag enumeration of harvesting seasons.
    [Flags]
    public enum Seasons
    {
        None = 0,
        Summer = 1,
        Autumn = 2,
        Winter = 4,
        Spring = 8
        All = Summer | Autumn | Winter | Spring,
    }

    somewhat contradictory statements, but note that All is here a member of the enum Seasons.

    Simplest solution in your case will be <strong>changing your flags into an int</strong>.

    Excuse me, it was late last night and spotted merely the neccessairy <strong>ref</strong>,  and didn't catch the type of flags.

  • Eric Springer

    You're right it works, but now it isn't generic anymore. I want to be able to use the method with any enum I define in my program. Your version only works with the enum 'Test'.

    By the way I don't see why you have to define the enum value AB = 3, it also works without it as far as I can tell! It would also be some VERY BIG enums if I had to define all the possible combinations of my enums with lets say 10 possible single values :-)

    Again many thanks for your help and time Aale!!

  • larsfp

    Hmm still don't work...

    The compiler can't automatically convert from 'Test' to 'int' in the method call - thats why I had the cast.

    Maybe I can't do this at all

  • Amarjeet

    Now I got curious myself and implemented to a test program:

    enum Test {A = 1, B = 2, AB = 3, C = 4};
    private void SetFlag(ref Test flags, Test flag)
    {
    flags |= flag;
    }
    private void SetFlag(ref int flags, Test flag)
    {
    flags |= (int) flag;
    }
    private void test()
    {
    int test = 0;

    SetFlag(ref test, Test.A);
    MessageBox.Show("test = " + test.ToString());
    SetFlag(ref test, Test.B);
    MessageBox.Show("test = " + test.ToString());

    Test ORTEST = Test.A;
    SetFlag(ref ORTEST, Test.B);
    MessageBox.Show("ORTEST = " + ORTEST.ToString());
    }

    A run of test() showed me the messages "test = 1" and "test = 3" and also "ORTEST = AB", so the darn thing works, the last olso shows the the first version works, but as said you need to define the possible values as part of your enum.
    Seccond argument merely B turns out to be faulty, the cast to (int)  the compiler told me to add, I thought given the definition of Test that would be implicit, but I was probably correctly mistaken.

  • msec

    If you want to use it for any enum you define, use int in stead of Test and cast to int in your call to the function.

    If you want true Generics you have to wait a while for Whidbey, the next version of c# has true Generics class support (I'm told) :) 

  • Bit fields