如何在不需要计算器的情况下将枚举定义为2的标志/幂?

我知道我可以乘法,但懒惰的编程,我是我不想。

有没有人发明了某种魔法,把枚举数自动编号为二的幂?

下面是我举的具体例子:

[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
}
14347 次浏览

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.
}

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.

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

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,
}
#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
};

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.

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

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