Enumerations IN C#

Enumerations are useful when a value in the program can have a specific set of values only. For example, when a control can be only one of four colors, or when a network package can support only two protocols, an enumeration can improve the code.

1. A Line-Style Enumeration

In the following example, a line-drawing class uses an enumeration to declare the styles of lines it can draw:

using System; public class Draw {

public enum LineStyle {

Solid,

Dotted,

DotDash,                  // trailing comma is optional

}

public void DrawLine(int x1, int y1, int x2, int y2, LineStyle lineStyle)

{

switch (lineStyle)

{

case LineStyle.Solid:

// draw solid

break;

case LineStyle.Dotted:

// draw dotted

break;

case LineStyle.DotDash:

// draw dotdash

break;

default:

throw(new ArgumentException(“Invalid line style”));

}

}

}

class Test {

public static void Main()

{

Draw draw = new Draw();

draw.DrawLine(0, 0, 10, 10, Draw.LineStyle.Solid);

draw.DrawLine(5, 6, 23, 3, (Draw.LineStyle) 35);

}

}

The LineStyle enum defines the values that can be specified for the enum, and then that same enum is used in the function call to specify the type of line to draw.

Although enums prevent the accidental specification of values outside the enum range, the values that can be specified for an enum aren’t limited to the identifiers specified in the enum declaration. The second call to DrawLine() is legal, so an enum value passed into a function must still be validated to ensure it’s in the range of valid values. The Draw class throws an invalid argument exception if the argument is invalid.

2. Enumeration Base Types

Each enumeration has an underlying type that specifies how much storage is allocated for that enumeration. The valid base types for enumeration are byte, sbyte, short, ushort, int, uint, long, and ulong. If the base type isn’t specified, the base type defaults to int. The base type is specified by listing the base type after the enum name:

enum SmallEnum : byte {

A,

B,

C,

D

}

Specifying the base type can be useful if size is a concern or if the number of entries would exceed the number of possible values for int.

3. Initialization

By default, the value of the first enum member is set to 0 and incremented for each subsequent member. Specific values may be specified along with the member name:

enum Values {

A = 1,

B = 5,

C = 3,

D = 42

}

Computed values can also be used, as long as they depend only on values already defined in the enum:

enum Values {

A = 1,

B = 2,

C = A + B,

D = A * C + 33

}

If an enum is declared without a 0 value, this can lead to problems, since 0 is the default initialized value for the enum:

enum Values {

A = 1,

B = 2,

C = A + B,

D = A * C + 33

}

class Test {

public static void Member(Values value)

{

// do some processing here

}

public static void Main()

{

Values value = 0;

Member(value);

}

}

A member with the value 0 should always be defined as part of an enum.

4. Bit Flag Enums

Enums may also be used as bit flags by specifying a different bit value for each bit. Here’s a typical definition:

using System;

[Flags]

enum BitValues : uint {

NoBits = 0,

Bit1 = 0x00000001,

Bit2 = 0x00000002,

Bit3 = 0x00000004,

Bit4 = 0x00000008,

Bit5 = 0x00000010,

AllBits = 0xFFFFFFFF

}

class Test {

public static void Member(BitValues value)

{

// do some processing here

}

public static void Main()

{

Member(BitValues.Bit1 | BitValues.Bit2);

}

}

The [Flags] attribute before the enum definition is used so that designers and browsers can present a different interface for enums that are flag enums. In such enums, it makes sense to allow the user to OR several bits together, which doesn’t make sense for nonflag enums.

The Main() function ORs two bit values together and then passes the value to the member function.

5. Conversions

Enum types can be converted to their underlying type and back again with an explicit conversion:

enum Values

{

A = 1,

B = 5,

C = 3,

D = 42

}

class Test {

public static void Main()

{

Values v = (Values) 2;

int ival = (int) v;

}

}

The sole exception to this is that you can convert the literal 0 to an enum type without a cast. This is allowed so you can write the following code:

public void DoSomething(BitValues bv)

{

if (bv == 0)

{

}

}

You have to write the if statement as follows if this exception isn’t present:

if (bv == (BitValues) 0)

That’s not bad for this example, but it could be quite cumbersome in actual use if the enum is nested deeply in the hierarchy, like so:

if (bv == (CornSoft.PlotLibrary.Drawing.LineStyle.BitValues) 0)

That’s a lot of typing.

6. The System.Enum Type

Like the other predefined type, the Enum type has some methods that make enums in C# a fair bit more useful than enums in C++.

The first of these is that the ToString() function is overridden to return the textual name for an enum value so you can do the following:

using System;

enum Color {

red,

green,

yellow

}

public class Test {

public static void Main()

{

Color c = Color.red;

Console.WriteLine(“c is {0}”, c);

}

}

The example produces the following rather than merely giving the numeric equivalent of Color.red:

c is red

You can perform other operations as well: using System;

enum Color {

red,

green,

yellow

}

public class Test {

public static void Main()

{

Color c = Color.red;

// enum values and names

foreach (int i in Enum.GetValues(c.GetType()))

{

Console.WriteLine(“Value: {0} ({1})”, i, Enum.GetName(c.GetType(), i));

}

// or just the names

foreach (string s in Enum.GetNames(c.GetType()))

{

Console.WriteLine(“Name: {0}”, s);

}

// enum value from a string, ignore case

c = (Color) Enum.Parse(typeof(Color), “Red”, true);

Console.WriteLine(“string value is: {0}”, c);

// see if a specific value is a defined enum member

bool defined = Enum.IsDefined(typeof(Color), 5);

Console.WriteLine(“5 is a defined value for Color: {0}”, defined);

}

}

The output from this example is as follows:

Value: 0 (red)

Value: 1 (green)

Value: 2 (yellow)

Name: red

Name: green

Name: yellow

string value is: red

5 is a defined value for Color: False

In this example, the values and/or names of the enum constants can be fetched from the enum, and the string name for a value can be converted to an enum value. Finally, a value is checked to see if it’s the same as one of the defined constants.

Source: Gunnerson Eric, Wienholt Nick (2005), A Programmer’s Introduction to C# 2.0, Apress; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *