Any trick to defining an enum as flags/powers of 2 without eventually needing a calculator?

I know I can multiply but being the lazy programming I am I do not want to.

Has anyone devised some sorcery to auto number the enums as powers of two?

Here's the example I have just to make it concrete:

[Flags]
private enum Targets : uint
{
    None = 0,
    Campaigns = 1,
    CampaignGroups = 2,
    Advertisers = 4,
    AdvertiserGroups = 8,
    AffiliateGroups = 16,
    Affiliates = 32,
    Creatives = 64,
    DetailedLeads = 128,
    DetailedSales = 256,
    ProgramLeads = 512,
    CreativeDeployments = 1024,
    CampaignCategories = 2048,
    Payouts = 4096,
    All = uint.MaxValue
}

Solution 1:

Write the values as shifted bits and let the compiler do the math:

[Flags]
private enum Targets : uint
{
    None                = 0,
    Campaigns           = 1,
    CampaignGroups      = 2 << 0,
    Advertisers         = 2 << 1,
    AdvertiserGroups    = 2 << 2,
    AffiliateGroups     = 2 << 3,
    Affiliates          = 2 << 4,
    Creatives           = 2 << 5,
    DetailedLeads       = 2 << 6,
    DetailedSales       = 2 << 7,
    ProgramLeads        = 2 << 8,
    CreativeDeployments = 2 << 9,
    CampaignCategories  = 2 << 10,
    Payouts             = 2 << 11,
    // etc.
}

James's suggestion is a good one, too. In fact I like this way even better. You could also write it like this:

[Flags]
private enum Targets : uint
{
    None                = 0,
    Campaigns           = 1 << 0,
    CampaignGroups      = 1 << 1,
    Advertisers         = 1 << 2,
    AdvertiserGroups    = 1 << 3,
    AffiliateGroups     = 1 << 4,
    // etc.
}

Solution 2:

Using hexadecimal notation is a little simpler than decimal notation as well (no calculator required):

[Flags]
private enum Targets : uint
{
    None                = 0,
    Campaigns           = 0x01,
    CampaignGroups      = 0x02,
    Advertisers         = 0x04,
    AdvertiserGroups    = 0x08,
    AffiliateGroups     = 0x10,
    Affiliates          = 0x20,
    Creatives           = 0x40,
    DetailedLeads       = 0x80,
    DetailedSales       = 0x100,
    ProgramLeads        = 0x200,
    CreativeDeployments = 0x400,
    CampaignCategories  = 0x800,
    Payouts             = 0x1000,
    // and the pattern of doubling continues
    // 0x2000
    // 0x4000
    // 0x8000
    // 0x10000
}

Not quite as elegant as Cody and James' solutions, but requires no calculator.

Solution 3:

Fast forward five years into the future, and starting with C# 7.0 you can use the new numeric binary literal to simplify the enum flags declaration.

[Flags]
private enum Targets : uint
{
    None = 0,
    Campaigns =             0b0000_0000_0000_0001,
    CampaignGroups =        0b0000_0000_0000_0010,
    Advertisers =           0b0000_0000_0000_0100,
    AdvertiserGroups =      0b0000_0000_0000_1000,
    AffiliateGroups =       0b0000_0000_0001_0000,
    Affiliates =            0b0000_0000_0010_0000,
    Creatives =             0b0000_0000_0100_0000,
    DetailedLeads =         0b0000_0000_1000_0000,
    DetailedSales =         0b0000_0001_0000_0000,
    ProgramLeads =          0b0000_0010_0000_0000,
    CreativeDeployments =   0b0000_0100_0000_0000,
    CampaignCategories =    0b0000_1000_0000_0000,
    Payouts =               0b0001_0000_0000_0000,
    All = uint.MaxValue
}

https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#numeric-literal-syntax-improvements

Solution 4:

I do the following:

 using System;

 [Flags]
 public enum AnimalCharacteristics : long
 {
     Tail = 1 << AnimalCharacteristicsBitPositions.Tail,
     Eyes = 1 << AnimalCharacteristicsBitPositions.Eyes,
     Furry = 1 << AnimalCharacteristicsBitPositions.Furry,
     Bipedal = 1 << AnimalCharacteristicsBitPositions.Bipedal
 }

 internal enum AnimalCharacteristicsBitPositions : int
 {
     Tail = 0,
     Eyes,
     Furry,
     Bipedal
 }

 public class Program
 {
     public static void Main()
     {
         var human = AnimalCharacteristics.Eyes | AnimalCharacteristics.Bipedal;
         var dog = AnimalCharacteristics.Eyes | AnimalCharacteristics.Tail | AnimalCharacteristics.Furry;

         Console.WriteLine($"Human: {human} ({(long)human})");
         Console.WriteLine($"Dog: {dog} ({(long)dog})");
     }
 }

This has the benefit that you can easily reorder the entries and add new ones by simply putting them in both enums following the pattern. The bit position is dependent on the second enum. To skip bit positions you can just assign a number anywhere in the second enum and the compiler will continue counting from there.

Do note that the positions are one less than the actual bit position (if you call the least significant bit position 1). Of course, you can start them at 1, and subtract 1 from the bit shift in the first enum if you prefer.