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

C#Enums

C# Problem Overview


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
}

C# Solutions


Solution 1 - C#

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 - C#

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 - C#

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 - C#

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.

Solution 5 - C#

Here's yet another alternative approach:

[Flags]
public enum COURSECOMPONENT_T : int
{
    Everything = -1,
    Nothing = 0,
    AttendanceRegisters = 1,
    Checklists = 2 * AttendanceRegisters,
    Competencies = 2 * Checklists,
    Content = 2 * Competencies,
    CourseFiles = 2 * Content,
    Discussions = 2 * CourseFiles,
    DisplaySettings = 2 * Discussions,
    Dropbox = 2 * DisplaySettings,
    Faq = 2 * Dropbox,
    Forms = 2 * Faq,
    Glossary = 2 * Forms,
    Grades = 2 * Glossary,
    GradesSettings = 2 * Grades,
    Groups = 2 * GradesSettings,
    Homepages = 2 * Groups,
    IntelligentAgents = 2 * Homepages,
    Links = 2 * IntelligentAgents,
    LtiLink = 2 * Links,
    LtiTP = 2 * LtiLink,
    Navbars = 2 * LtiTP,
    News = 2 * Navbars,
    QuestionLibrary = 2 * News,
    Quizzes = 2 * QuestionLibrary,
    ReleaseConditions = 2 * Quizzes,
    Rubrics = 2 * ReleaseConditions,
    Schedule = 2 * Rubrics,
    SelfAssessments = 2 * Schedule,
    Surveys = 2 * SelfAssessments,
    ToolNames = 2 * Surveys,
    Widgets = 2 * ToolNames,
}

Solution 6 - C#

#define BITS  \
    F(Campaigns) \
    F(Quizzes) \
    F(Groups) \
    F(Homepages)

#define F(x) x##_BIT,

enum bits {
    BITS
};

#undef F
#define F(x) x = (1 << x##_BIT),

enum flags {
    BITS
};

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAaron AnodideView Question on Stackoverflow
Solution 1 - C#Cody GrayView Answer on Stackoverflow
Solution 2 - C#drew010View Answer on Stackoverflow
Solution 3 - C#joakimriedelView Answer on Stackoverflow
Solution 4 - C#smboganView Answer on Stackoverflow
Solution 5 - C#HughView Answer on Stackoverflow
Solution 6 - C#some guyView Answer on Stackoverflow