Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
65
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 22: Enum

An enum can derive from any of the following types: byte, sbyte, short, ushort, int, uint, long, ulong. The default is int, and can be changed by specifying the type in the enum definition:

public enum Weekday : byte { Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4, Friday = 5 }

This is useful when P/Invoking to native code, mapping to data sources, and similar circumstances. In general, the default int should be used, because most developers expect an enum to be an int.

Section 22.1: Enum basics

From MSDN:

An enumeration type (also named an enumeration or an enum) provides an e cient way to define a set of named integral constants that may be assigned to a variable.

Essentially, an enum is a type that only allows a set of finite options, and each option corresponds to a number. By default, those numbers are increasing in the order the values are declared, starting from zero. For example, one could declare an enum for the days of the week:

public enum Day

{

Monday,

Tuesday,

Wednesday,

Thursday,

Friday,

Saturday, Sunday

}

That enum could be used like this:

//Define variables with values corresponding to specific days

Day myFavoriteDay = Day.Friday;

Day myLeastFavoriteDay = Day.Monday;

//Get the int that corresponds to myFavoriteDay

//Friday is number 4

int myFavoriteDayIndex = (int)myFavoriteDay;

// Get the day that represents number 5

Day dayFive = (Day)5;

By default the underlying type of each element in the enum is int, but byte, sbyte, short, ushort, uint, long and ulong can be used as well. If you use a type other than int, you must specify the type using a colon after the enum name:

public enum Day : byte

{

// same as before

}

GoalKicker.com – C# Notes for Professionals

98

The numbers after the name are now bytes instead of integers. You could get the underlying type of the enum as follows:

Enum.GetUnderlyingType(typeof(Days)));

Output:

System.Byte

Demo: .NET fiddle

Section 22.2: Enum as flags

The FlagsAttribute can be applied to an enum changing the behaviour of the ToString() to match the nature of the enum:

[Flags] enum MyEnum

{

//None = 0, can be used but not combined in bitwise operations

FlagA = 1,

FlagB = 2,

FlagC = 4,

FlagD = 8

//you must use powers of two or combinations of powers of two //for bitwise operations to work

}

var twoFlags = MyEnum.FlagA | MyEnum.FlagB;

// This will enumerate all the flags in the variable: "FlagA, FlagB".

Console.WriteLine(twoFlags);

Because FlagsAttribute relies on the enumeration constants to be powers of two (or their combinations) and enum values are ultimately numeric values, you are limited by the size of the underlying numeric type. The largest available numeric type that you can use is UInt64, which allows you to specify 64 distinct (non-combined) flag enum constants. The enum keyword defaults to the underlying type int, which is Int32. The compiler will allow the declaration of values wider than 32 bit. Those will wrap around without a warning and result in two or more enum members of the same value. Therefore, if an enum is meant to accomodate a bitset of more than 32 flags, you need to specify a bigger type explicitely:

public enum BigEnum : ulong

{

BigValue = 1 << 63

}

Although flags are often only a single bit, they can be combined into named "sets" for easier use.

[Flags]

enum FlagsEnum

{

None = 0, Option1 = 1, Option2 = 2, Option3 = 4,

Default = Option1 | Option3,

GoalKicker.com – C# Notes for Professionals

99

All = Option1 | Option2 | Option3,

}

To avoid spelling out the decimal values of powers of two, the left-shift operator (<<) can also be used to declare the same enum

[Flags]

enum FlagsEnum

{

None = 0, Option1 = 1 << 0, Option2 = 1 << 1, Option3 = 1 << 2,

Default = Option1 | Option3,

All = Option1 | Option2 | Option3,

}

Starting with C# 7.0, binary literals can be used too.

To check if the value of enum variable has a certain flag set, the HasFlag method can be used. Let's say we have

[Flags] enum MyEnum

{

One = 1,

Two = 2,

Three = 4

}

And a value

var value = MyEnum.One | MyEnum.Two;

With HasFlag we can check if any of the flags is set

if(value.HasFlag(MyEnum.One)) Console.WriteLine("Enum has One");

if(value.HasFlag(MyEnum.Two)) Console.WriteLine("Enum has Two");

if(value.HasFlag(MyEnum.Three)) Console.WriteLine("Enum has Three");

Also we can iterate through all values of enum to get all flags that are set

var type = typeof(MyEnum);

var names = Enum.GetNames(type);

foreach (var name in names)

{

var item = (MyEnum)Enum.Parse(type, name);

if (value.HasFlag(item)) Console.WriteLine("Enum has " + name);

}

GoalKicker.com – C# Notes for Professionals

100

Or

foreach(MyEnum flagToCheck in Enum.GetValues(typeof(MyEnum)))

{

if(value.HasFlag(flagToCheck))

{

Console.WriteLine("Enum has " + flagToCheck);

}

}

All three examples will print:

Enum has One

Enum has Two

Section 22.3: Using << notation for flags

The left-shift operator (<<) can be used in flag enum declarations to ensure that each flag has exactly one 1 in binary representation, as flags should.

This also helps to improve readability of large enums with plenty of flags in them.

[Flags]

public enum MyEnum

{

None

= 0,

 

Flag1

= 1 << 0,

Flag2

= 1 << 1,

Flag3

= 1 << 2,

Flag4

= 1

<< 3,

Flag5

= 1

<< 4,

...

 

 

Flag31 = 1

<< 30

}

It is obvious now that MyEnum contains proper flags only and not any messy stu like Flag30 = 1073741822 (or 111111111111111111111111111110 in binary) which is inappropriate.

Section 22.4: Test flags-style enum values with bitwise logic

A flags-style enum value needs to be tested with bitwise logic because it may not match any single value.

[Flags]

enum FlagsEnum

{

Option1 = 1,

Option2 = 2,

Option3 = 4,

Option2And3 = Option2 | Option3;

Default = Option1 | Option3,

}

The Default value is actually a combination of two others merged with a bitwise OR. Therefore to test for the presence of a flag we need to use a bitwise AND.

var value = FlagsEnum.Default;

GoalKicker.com – C# Notes for Professionals

101