Любой трюк для определения перечисления как флагов/полномочий 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
}
Ответы
Ответ 1
Запишите значения как сдвинутые биты и пусть компилятор выполнит математику:
[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.
}
Предложение Джеймса тоже хорошее. На самом деле мне нравится этот путь еще лучше. Вы также можете написать это следующим образом:
[Flags]
private enum Targets : uint
{
None = 0,
Campaigns = 1 << 0,
CampaignGroups = 1 << 1,
Advertisers = 1 << 2,
AdvertiserGroups = 1 << 3,
AffiliateGroups = 1 << 4,
// etc.
}
Ответ 2
Использование шестнадцатеричной нотации немного проще, чем десятичная нотация (калькулятор не требуется):
[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
}
Не так элегантно, как решения Коди и Джеймса, но не требует калькулятора.
Ответ 3
Ускорьте вперед на пять лет вперед и, начиная с С# 7.0, вы можете использовать новый числовой двоичный литерал, чтобы упростить объявление флагов перечисления.
[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
Ответ 4
Вот еще один альтернативный подход:
[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,
}
Ответ 5
Я делаю следующее:
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})");
}
}
Это дает то преимущество, что вы можете легко изменить порядок записей и добавить новые, просто поместив их в оба перечисления, следуя шаблону. Положение бита зависит от второго перечисления. Чтобы пропустить битовые позиции, вы можете просто присвоить число где-нибудь во втором перечислении, и компилятор продолжит отсчет оттуда.
Обратите внимание, что позиции на единицу меньше, чем фактическая битовая позиция (если вы называете младшую битовую позицию 1). Конечно, вы можете начать их с 1 и вычесть 1 из сдвига битов в первом перечислении, если хотите.
Ответ 6
#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
};