Quantcast
Channel: Xie 's Blog
Viewing all articles
Browse latest Browse all 10

[C#] Enumeration Types Summary

$
0
0

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

Usually it is best to define an enum directly within a namespace so that all classes in the namespace can access it with equal convenience. However, an enum can also be nested within a class or struct.

Every enumeration type has an underlying type (byte, sbyte, short, ushort, int, uint, long, or ulong), which can be any integral type except char. The default underlying type of enumeration elements is int. To declare an enum of another integral type, such as byte, use a colon after the identifier followed by the type.

The default value of an enum E is the value produced by the expression (E)0, and the value of each successive enumerator is increased by 1 if it’s not explicitly assigned. When you create an enum, select the most logical default value and give it a value of zero, or you can consider creating a None enumerated constant. That will cause all enums to have that default value if they are not explicitly assigned a value when they are created.

When assigning values to the elements in the enumerator list, you can also use coputed values, for example:

enum MachineState
{
PowerOff = 0,
Running = 5,
Sleeping = 10,
Hibernating = Sleeping + 5
}

Enumeration Types as Bit Flags

You create a bit flags enum by applying the System.FlagsAttribute attribute and defining the values appropriately so that AND, OR, NOT and XOR bitwise operations can be performed on them. In a bit flags enum, include a named constant with a value of zero that means “no flags are set.”(always None.) Do not give a flag a value of zero if it does not mean “no flags are set”.

If a enumeration type has the flags attribute, each value should be assigned the next greater power of 2. It’s very convenient to use hexadecimal numbers here. For example:

[Flags]
enum Days2
{
 None = 0x0,
 Sunday = 0x1,
 Monday = 0x2,
 Tuesday = 0x4,
 Wednesday = 0x8,
 Thursday = 0x10,
 Friday = 0x20,
 Saturday = 0x40
}
class MyClass
{
 Days2 meetingDays = Days2.Tuesday | Days2.Thursday;
}

OR, XOR, AND, NOT operations on enumeration types with Flags Attribute:

// Initialize with two flags using bitwise OR.
meetingDays = Days2.Tuesday | Days2.Thursday;

// Set an additional flag using bitwise OR.
meetingDays = meetingDays | Days2.Friday;

Console.WriteLine("Meeting days are {0}", meetingDays);
// Output: Meeting days are Tuesday, Thursday, Friday

// Test value of flags using bitwise AND.
bool test = (meetingDays & Days2.Thursday) == Days2.Thursday;
//Notice: Simply use instance method <em><strong>HasFlag</strong></em> of enum type instead.

Console.WriteLine("Thursday {0} a meeting day.", test == true ? "is" : "is not");
// Output: Thursday is a meeting day.

// Remove a flag using bitwise XOR.
meetingDays = meetingDays ^ Days2.Tuesday;
Console.WriteLine("Meeting days are {0}", meetingDays);
// Output: Meeting days are Thursday, Friday

/* Notice: In this example, if Day2.Tuesday is not originally included in the enumeration variable meetingDays, the XOR operation will add Day2.Tuesday to it. There are two ways to remove item safely. */
// #1: Use <strong>AND</strong> operation or <strong>HasFlag</strong> method
if (meetingDays.HasFlag(Days2.Tuesday))
    meetingDays = meetingDays ^ Days2.Tuesday;
// #2: Use <strong>~</strong> operation with <strong>AND</strong>
meetingDays = meetingDays & (~Days2.Tuesday);

System.Enum Methods

You cannot define new methods when you are creating an enumeration. However, an enumeration type inherits a complete set of static and instance methods from the Enum class.

string s = Enum.GetName(typeof(Days), 4);
Console.WriteLine(s);

Console.WriteLine("The values of the Days Enum are:");
foreach (int i in Enum.GetValues(typeof(Days)))
 Console.WriteLine(i);

Console.WriteLine("The names of the Days Enum are:");
foreach (string str in Enum.GetNames(typeof(Days)))
 Console.WriteLine(str);

Frequently Used Methods:

GetName: Retrieves the name of the constant in the specified enumeration that has the spedified value.

GetNames: Retrieves an array of the names of the constants in a specified enumeration.

GetValues: Retrieves an array of the values of the constants in a spedified enumeration.

GetUnderlyingType: Returns the underlying type of the specified enumeration.

HasFlag: Determines whether one or more bit fields are set in the current instance.

IsDefined: static method, it returns an indication whether a constant with a specified value exists in a specified enumeration. Notice that if enumType is an enumeration that is defined by using the FlagsAttribute attribute, the method returns false if multiple bit fields in value are set but valuedoes not correspond to a composite enumeration value, or if value is a string concatenation of the names of multiple bit flags.

Validating Enumeration Values:

It is possible to assign any arbitrary integer value to a variable of an enumeration type even if that numeric value is not defined in the enumeration. However, you should not do this as it introduces a high risk for errors.

When you define a method or property that takes an enumerated constant as a value, consider validating the value.

The static method Enum.IsDefined is helpful to do this. Considering the FlagsAttribute attribute, the following code is useful:

 if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))

Convertions and Convertion Methods

The enumeration members must be explicitly converted to its underlying type by using a explicit type casting, and vice versa.

However, we have more safely approaches instead of type casting.

1. Convertion from an enumeration value to a integral value:

1.1 Type Casting

Type casting is no doubt the simplest way to perform this convertion, but it’s not recommended by MSDN.

1.2 Instance Methods of IConvertible Interface

the Enum class provides explicit interface implementations of the IConvertible interface for converting from an enumeration value to an integral type. Consequently you can use abundant instance methods such as enum.ToInt32 method to convert an enum to an integer.

Somehow, it’s not recommended by MSDN either. (see Enum Class)

1.3 Static Methods of Convert class

Oh! These methods seem familiar to you,such as Convert.ToInt32. Note that you can use the GetUnderlyingType method along with the Convert.ChangeType method to convert an enumeration value to its underlying type even if you the underlying type is unknown.

ArrivalStatus status = ArrivalStatus.Early;
var number = Convert.ChangeType(status, Enum.GetUnderlyingType(typeof(ArrivalStatus)));
Console.WriteLine("Converted {0} to {1}", status, number);

2. Convertion from an integral value to an enumeration value

2.1 general type casting, “(enum) value”, also not recommended.

2.2 Static method ToObject(EnumType, Value)

int number = -1;
ArrivalStatus arrived = (ArrivalStatus) Enum.ToObject(typeof(ArrivalStatus), number);

Note that, because the ToObject returns a value of type Object, the use of a casting or conversion operator may still be necessary to cast the object to the enumeration type.

Attention: When converting an integer to an enumeration value, it is possible to assign a value that is not actually a member of the enumeration. To prevent this, you can pass the integer to the IsDefined method before performing the conversion.

3. Parse a string that contains the name of a constant in the enumeration

There are 2 static methods: Parse and TryParse methods, total 4 overloaded versions.

3.1 Parse method:

Parse(Type, String)
Parse(Type, String, Boolean)

They Convert the string representation of the name or numeric value of an enumerated constant to an equivalent enumerated object. A parameter specifies whether the operation is case-insensitive. The former overloaded version that takes 2 arguments is Case-Sensitive.

If string value is a name that does not correspond to a named constant of enumType, the method throws an ArgumentException. But if value is the string representation of an integer that does not represent an underlying value of the enumType enumeration, the method returns an enumeration member whose underlying value is value converted to an integral type. If this behavior is undesirable, call the IsDefined method to ensure that a particular string representation of an integer is actually a member of enumType.

Fortunately, we do not usually need to parse a string which represents an integer.

3.2 generic method TryParse

TryParse<TEnum>(String, TEnum)
TryParse<TEnum>(String, Boolean, TEnum)

These two methods are identical to the Parse(Type, String) and Parse(Type, String, Boolean) methods, except that instead of throwing an exception, they return false if the conversion fails. It eliminates the need of exception handling when parsing the string representation of an enumeration value.

4. Get the name of an enumeration variable.

As most objects, You can use the Enum.ToString method to create a new string object that represents the string value of an enumeration member. The method can also create the numeric or hexadecimal value of the enumeration member. So you may need the Enumeration Format Strings to specify the value that you want returned.

Extension Method

You can also create a new method for an enum by using an extension method.

In the following example, the Grades enumeration represents the possible letter grades that a student may receive in a class. An extension method named Passing is added to the Grades type so that each instance of that type now “knows” whether it represents a passing grade or not.

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace EnumExtension
{
 // Define an extension method in a non-nested static class.
 public static class Extensions
 {
 public static Grades minPassing = Grades.D;
 public static bool Passing(this Grades grade)
 {
 return grade >= minPassing;
 }
 }

public enum Grades { F = 0, D=1, C=2, B=3, A=4 };
 class Program
 {
 static void Main(string[] args)
 {
 Grades g1 = Grades.D;
 Grades g2 = Grades.F;
 Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
 Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");

Extensions.minPassing = Grades.C;
 Console.WriteLine("\r\nRaising the bar!\r\n");
 Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
 Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
 }
 }
 }
}
/* Output:
 First is a passing grade.
 Second is not a passing grade.

Raising the bar!

First is not a passing grade.
 Second is not a passing grade.
*/

Extension methods enable you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.

Extension methods are defined as static methods but are called by using instance method syntax. Their first parameter specifies which type the method operates on, and the parameter is preceded by the this modifier. Extension methods are only in scope when you explicitly import the namespace into your source code with a using directive.

The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable<T> types.

References

[1] Enum Class

[2] Enum (C# Reference)

[3] Enumeration Types (C# Programming Guide)

[4] How to: Create a New Method for an Enumeration (C# Programming Guide)

[5] Extension Methods (C# Programming Guide)


Viewing all articles
Browse latest Browse all 10

Latest Images

Trending Articles





Latest Images