Enumerated Types in C#

An enumerated type, or enum as it’s called in C#, offers a convenient way to create a structured set of symbols to represent constant values.

Syntax:

[access modifiers]enum <identifier> [:enum-base]{enum body}

Example:

enum Fabric :short {

   Cotton = 1,  

   Silk   = 2,  

   Wool   = 4,  

   Rayon  = 8,  

   Other  = 128 

}

Note: If the enum symbols are not set to a value, they are set automatically to the sequence 0, 1, 2, 3, and so on.

The access modifiers define the scope of the enum. The default is internal, which permits it to be accessed by any class in its assembly. Use public to make it available to any class in any assembly.

The optional enum-base defines the underlying type of the constants that correspond to the symbolic names. This must be an integral value of the type byte, sbyte, short, ushort, int, uint, long, or ulong. The default is int.

Working with Enumerations

Enumerated types not only improve program readability, but also minimize code changes when the underlying value changes. In such cases, all references to the value remain valid. Another advantage is that enumerated types are strongly typed. This means, for example, that when an enum type is passed as a parameter, the receiving method must have a matching parameter of the same type; otherwise, a compiler error occurs.

 Using an Enumerated Type
static double GetPrice(Fabric fab)

{

   switch(fab)

   {

      case Fabric.Cotton: return(3.55);

      case Fabric.Silk:   return(5.65);

      case Fabric.Wool:   return(4.05);

      case Fabric.Rayon:  return(3.20);

      case Fabric.Other:  return(2.50);

      default: return(0.0);

   }

}

static void Main()     

{

   Fabric fab = Fabric.Cotton;

   int fabNum   = (int) fab;             // 1

   string fabType =  fab.ToString();     // "Cotton"

   string fabVal  =  fab.ToString("D");  // "1"

   double cost = GetPrice(fab);          // 3.55

} 

Things to note:

  • Casting is required to set the value of an enum to an integer variable: fabNum = (int) fab;

  • The character value of the underlying constant value can be obtained using the ToString() method with the parameter "D". "D" is a format character that converts a value to its decimal form.

  • Passing an instance of the Fabric enum to GetPrice requires that the corresponding parameter in the GetPrice method is declared as the same type.

This example shows how easy it is to obtain the symbol name or constant value when the instance of an enum is known—that is, Cotton. But suppose there is a need to determine whether an enum contains a member with a specific symbol or constant value. You could use foreach to loop through the enum members, but there is a better solution. Enumerations implicitly inherit from System.Enum, and this class contains a set of methods that can be used to query an enumeration about its contents.

System.Enum Methods

Three of the more useful System.Enum methods are Enum.IsDefined, Enum.Parse, and Enum.GetName. The first two methods are often used together to determine if a value or symbol is a member of an enum, and then to create an instance of it. The easiest way to understand them is to see them in use. In this example, the enum Fabric is queried to determine if it contains a symbol matching a given string value. If so, an instance of the enum is created and the GetName method is used to print one of its values.

string fabStr = "Cotton";

// Determine if symbol Cotton exists in Fabric enum

if (Enum.IsDefined(typeof(Fabric),fabStr)) 

{

   // Create enum instance

   Fabric fab = (Fabric)Enum.Parse(

                 typeof(Fabric) , fabStr);

   // Output from the following statement is: "Silk"

   Console.WriteLine("Second value of Fabric Enum is: " +

                     Enum.GetName(typeof(Fabric), 2));      

}

The IsDefined method takes two parameters: an enumeration type that the typeof operator returns and a string representing the symbol to be tested for. Another form of this method tests for a specified constant value if a numeric value is passed as the second parameter.

The Parse method takes the same arguments and creates an instance of an enumerated type. The variable fab created here is equivalent to the one created in Listing 2-2. It is important to ensure that the enum member exists before using the Parse method. If it does not, an exception is thrown.

The GetName method returns a string value of the enum whose value is passed as the second argument to the method. In this example, "Silk" is returned because its constant value is 2.

Enums and Bit Flags

It was not by accident that the values of the Fabric enum were set to powers of 2. Enum members are often used in logical operations where such values have obvious advantages in mapping to unique bit values. You may have code to identify a combination of values:

Fabric cotWool = Fabric.Cotton | Fabric.Wool;

Console.WriteLine(cotWool.ToString());  // Output: 5

It would be more meaningful if the output identified the variable as a combination of wool and cotton. This can be accomplished by adding the [Flags] attribute to the enum declaration:

[Flags]

enum Fabric :short {

The ToString() method checks an enum declaration to see if this attribute is present. If so, it treats the enum as a set of bitmapped flag elements. In this example, it cannot find a symbolic value equal to 5, so it uses the bit pattern “101” and prints the symbols having the bit patterns “001” and “100”. The new output is a comma- delimited list: “Cotton, Wool”.

Leave a Reply

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