79

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
}
Aaron Anodide
  • 16,906
  • 15
  • 62
  • 121
  • 3
    Multiply the prior value by 2? – Tim M. May 11 '12 at 21:06
  • 8
    easiest thing is to memorize them up to 2^64? – JeremyWeir May 11 '12 at 21:07
  • 4
    That's what calculators are for. You should use hex values just to stay practiced with multiplying base 16. :) – IAbstract May 11 '12 at 21:08
  • Possible duplicate: http://stackoverflow.com/questions/8447/enum-flags-attribute (my first vote to close contained the wrong url) – ChristopheD May 11 '12 at 21:12
  • 1
    The only thing I don't like about these shortcuts is if you happen to save these enums in the database as ints. Then you have to get the calculator out a lot more than once to figure out what values correspond to which enum. – JeremyWeir May 14 '12 at 06:06

6 Answers6

140

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.
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 29
    I do something similar except instead of 2, i use 1 << 1, 1 << 2, 1 << 3, etc. – James Michael Hare May 11 '12 at 21:09
  • 3
    Since the underlying type of your enum is `uint`, it's really `1u << 0`, `1u << 1` etc. That might be important when you come to `LastFlag = 1u << 31`. – Jeppe Stig Nielsen May 11 '12 at 22:33
  • `1 << n` is shorthand for **bit n**. As in, if I wanted to set bits 2, 3, and 6 of a number, I'd set the number to `(1 << 2) | (1 << 3) | (1 << 6)`. The number you shift by has direct correlation to the bit number you're operating on. – indiv May 12 '12 at 00:40
  • 1
    The cleanest looking answer, but sadly Visual Studio has a habit of tidying up your whitespace. – Kyle Baran May 15 '15 at 12:14
  • when do `1 << 31` got error `Constant value '-2147483648' cannot be converted to a 'uint'`. Should use `1U` instead `1` as suggested by @JeppeStigNielsen – anonymous Jan 30 '20 at 10:22
  • Yes, @anonymous; you want an unsigned int rather than a signed int. – Cody Gray - on strike Jan 30 '20 at 19:36
45

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.

drew010
  • 68,777
  • 11
  • 134
  • 162
  • 2
    I have seen this system widely used many times. so it is good to know it when you encounter code that uses it. I use `1<<` personally – v.oddou Nov 21 '14 at 07:30
  • This system is better when you have to know on which bytes you set flags. That is why I prefer this ;) – Skorek Apr 12 '19 at 11:03
  • I think the first numbers can be 0x1, 0x2, 0x4, 0x8, with no leading zero. This would become a more obvious pattern. – Akenolt Aug 12 '21 at 11:50
10

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://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#numeric-literal-syntax-improvements

joakimriedel
  • 1,801
  • 12
  • 27
  • Of course the whole thing can be automated by introducing a new overload for the Flags attribute class that takes a bool "Auto". So [Flags(true)] could then serve to have the enum automatically populated by continual left bit shifting each member. – Hugh Dec 09 '17 at 15:20
  • As far as I know, the Flags attribute does nothing except help formatting the string representation of the value. I'm not sure whether a new kind of attribute could override the compiler behavior on automatic enum values generation. – Akenolt Aug 12 '21 at 11:53
2

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.

smbogan
  • 91
  • 1
  • 3
  • Keep in mind that unless I'm missing something, reordering values means modifying values which would be a breaking change and have the potential to corrupt any stored data. – bkqc Jul 18 '22 at 17:53
0

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,
}
Hugh
  • 748
  • 9
  • 9
  • 5
    This kind of notation is very tricky and decreases code readability. With this notation it would be hard to change values order (if required). – Skorek Apr 12 '19 at 11:02
0

public enum ColumnsWeight { Column1 = 0, Column2, Column3, Column4 };

if (4 == Math.Pow(2, (double)ColumnsWeight.Column3)) { // Do something for Column3 }

Xerx
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 21 '22 at 08:19