Search code examples
c#enumerationendiannessflags

Large flags enumerations in C#


Hey everyone, got a quick question that I can't seem to find anything about...

I'm working on a project that requires flag enumerations with a large number of flags (up to 40-ish), and I don't really feel like typing in the exact mask for each enumeration value:

public enum MyEnumeration : ulong
{
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8,
    Flag5 = 16,
    // ...
    Flag16 = 65536,
    Flag17 = 65536 * 2,
    Flag18 = 65536 * 4,
    Flag19 = 65536 * 8,
    // ...
    Flag32 = 65536 * 65536,
    Flag33 = 65536 * 65536 * 2
    // right about here I start to get really pissed off
}

Moreover, I'm also hoping that there is an easy(ier) way for me to control the actual arrangement of bits on different endian machines, since these values will eventually be serialized over a network:

public enum MyEnumeration : uint
{
    Flag1 = 1,     // BIG: 0x00000001, LITTLE:0x01000000
    Flag2 = 2,     // BIG: 0x00000002, LITTLE:0x02000000
    Flag3 = 4,     // BIG: 0x00000004, LITTLE:0x03000000
    // ...
    Flag9 = 256,   // BIG: 0x00000010, LITTLE:0x10000000
    Flag10 = 512,  // BIG: 0x00000011, LITTLE:0x11000000
    Flag11 = 1024  // BIG: 0x00000012, LITTLE:0x12000000
}

So, I'm kind of wondering if there is some cool way I can set my enumerations up like:

public enum MyEnumeration : uint
{
     Flag1 = flag(1), // BOTH: 0x80000000
     Flag2 = flag(2), // BOTH: 0x40000000
     Flag3 = flag(3), // BOTH: 0x20000000
     // ...
     Flag9 = flag(9), // BOTH: 0x00800000
}

What I've Tried:

// this won't work because Math.Pow returns double
// and because C# requires constants for enum values
public enum MyEnumeration : uint
{
    Flag1 = Math.Pow(2, 0),
    Flag2 = Math.Pow(2, 1)
}

// this won't work because C# requires constants for enum values
public enum MyEnumeration : uint
{
    Flag1 = Masks.MyCustomerBitmaskGeneratingFunction(0)
}

// this is my best solution so far, but is definitely
// quite clunkie
public struct EnumWrapper<TEnum> where TEnum
{
    private BitVector32 vector;
    public bool this[TEnum index]
    {
         // returns whether the index-th bit is set in vector
    }
    // all sorts of overriding using TEnum as args
}

Just wondering if anyone has any cool ideas, thanks!


Solution

  • You could write a T4 template to generate the enum :

    Template (MyEnumeration.tt)

    <#@ template language="C#" #>
    <#@ output extension=".cs" #>
    using System;
    
    namespace MyNamespace
    {
        [Flags]
        public enum MyEnumeration : ulong
        {
    <#
        ulong value = 1;
        for(int i = 1; i <= 64; i++)
        {
    #>
            Flag<#= i #> = <#= string.Format("0x{0:X8}", value) #>,
    <#
            value = value << 1;
        }
    #>
        }
    }
    

    Resulting C# code (MyEnumeration.cs)

    using System;
    
    namespace MyNamespace
    {
        [Flags]
        public enum MyEnumeration : ulong
        {
            Flag1 = 0x00000001,
            Flag2 = 0x00000002,
            Flag3 = 0x00000004,
            Flag4 = 0x00000008,
            Flag5 = 0x00000010,
            Flag6 = 0x00000020,
            Flag7 = 0x00000040,
            Flag8 = 0x00000080,
            Flag9 = 0x00000100,
            Flag10 = 0x00000200,
            Flag11 = 0x00000400,
            Flag12 = 0x00000800,
            Flag13 = 0x00001000,
            Flag14 = 0x00002000,
            Flag15 = 0x00004000,
            Flag16 = 0x00008000,
            Flag17 = 0x00010000,
            Flag18 = 0x00020000,
            Flag19 = 0x00040000,
            Flag20 = 0x00080000,
            Flag21 = 0x00100000,
            Flag22 = 0x00200000,
            Flag23 = 0x00400000,
            Flag24 = 0x00800000,
            Flag25 = 0x01000000,
            Flag26 = 0x02000000,
            Flag27 = 0x04000000,
            Flag28 = 0x08000000,
            Flag29 = 0x10000000,
            Flag30 = 0x20000000,
            Flag31 = 0x40000000,
            Flag32 = 0x80000000,
            Flag33 = 0x100000000,
            Flag34 = 0x200000000,
            Flag35 = 0x400000000,
            Flag36 = 0x800000000,
            Flag37 = 0x1000000000,
            Flag38 = 0x2000000000,
            Flag39 = 0x4000000000,
            Flag40 = 0x8000000000,
            Flag41 = 0x10000000000,
            Flag42 = 0x20000000000,
            Flag43 = 0x40000000000,
            Flag44 = 0x80000000000,
            Flag45 = 0x100000000000,
            Flag46 = 0x200000000000,
            Flag47 = 0x400000000000,
            Flag48 = 0x800000000000,
            Flag49 = 0x1000000000000,
            Flag50 = 0x2000000000000,
            Flag51 = 0x4000000000000,
            Flag52 = 0x8000000000000,
            Flag53 = 0x10000000000000,
            Flag54 = 0x20000000000000,
            Flag55 = 0x40000000000000,
            Flag56 = 0x80000000000000,
            Flag57 = 0x100000000000000,
            Flag58 = 0x200000000000000,
            Flag59 = 0x400000000000000,
            Flag60 = 0x800000000000000,
            Flag61 = 0x1000000000000000,
            Flag62 = 0x2000000000000000,
            Flag63 = 0x4000000000000000,
            Flag64 = 0x8000000000000000,
        }
    }
    

    In order to edit T4 templates, I recommend you use a T4 editor plugin like this one (this gives you syntax highlighting and Intellisense)