Enum Class
Provides the base class for enumerations.
Assembly: mscorlib (in mscorlib.dll)
An enumeration is a named constant whose underlying type is any integral type except Char. If no underlying type is explicitly declared, Int32 is used. Programming languages typically provide syntax to declare an enumeration that consists of a set of named constants and their values.
Caution:
|
|---|
|
You should never create an enumeration type whose underlying type is non-integral. Although you can create such an enumeration type by using reflection, method calls that use the resulting type are unreliable and may also throw additional exceptions. |
Enum provides methods to compare instances of this class, convert the value of an instance to its string representation, convert the string representation of a number to an instance of this class, and create an instance of a specified enumeration and value.
You can also treat an enumeration as a bit field. For more information, see FlagsAttribute.
Implemented Interfaces
This class inherits from ValueType, and implements the IComparable, IFormattable, and IConvertible interfaces. Use the Convert class for conversions instead of this class' explicit interface member implementation of IConvertible.
Guidelines for FlagsAttribute and Enum
-
Use the FlagsAttribute custom attribute for an enumeration only if a bitwise operation (AND, OR, EXCLUSIVE OR) is to be performed on a numeric value.
-
Define enumeration constants in powers of two, that is, 1, 2, 4, 8, and so on. This means the individual flags in combined enumeration constants do not overlap.
-
Consider creating an enumerated constant for commonly used flag combinations. For example, if you have an enumeration used for file I/O operations that contains the enumerated constants Read = 1 and Write = 2, consider creating the enumerated constant ReadWrite = Read OR Write, which combines the Read and Write flags. In addition, the bitwise OR operation used to combine the flags might be considered an advanced concept in some circumstances that should not be required for simple tasks.
-
Use caution if you define a negative number as a flag enumerated constant because many flag positions might be set to 1, which might make your code confusing and encourage coding errors.
-
A convenient way to test whether a flag is set in a numeric value is to perform a bitwise AND operation between the numeric value and the flag enumerated constant, which sets all bits in the numeric value to zero that do not correspond to the flag, then test whether the result of that operation is equal to the flag enumerated constant.
-
Use None as the name of the flag enumerated constant whose value is zero. You cannot use the None enumerated constant in a bitwise AND operation to test for a flag because the result is always zero. However, you can perform a logical, not a bitwise, comparison between the numeric value and the None enumerated constant to determine whether any bits in the numeric value are set.
If you create a value enumeration instead of a flags enumeration, it is still worthwhile to create a None enumerated constant. The reason is that by default the memory used for the enumeration is initialized to zero by the common language runtime. Consequently, if you do not define a constant whose value is zero, the enumeration will contain an illegal value when it is created.
If there is an obvious default case your application needs to represent, consider using an enumerated constant whose value is zero to represent the default. If there is no default case, consider using an enumerated constant whose value is zero that means the case that is not represented by any of the other enumerated constants.
-
Do not define an enumeration value solely to mirror the state of the enumeration itself. For example, do not define an enumerated constant that merely marks the end of the enumeration. If you need to determine the last value of the enumeration, check for that value explicitly. In addition, you can perform a range check for the first and last enumerated constant if all values within the range are valid.
-
Do not specify enumerated constants that are reserved for future use.
-
When you define a method or property that takes an enumerated constant as a value, consider validating the value. The reason is that you can cast a numeric value to the enumeration type even if that numeric value is not defined in the enumeration.
The following example demonstrates using an enumeration to represent named values and another enumeration to represent named bit fields.
using System; public class EnumTest { enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday }; enum BoilingPoints { Celsius = 100, Fahrenheit = 212 }; [FlagsAttribute] enum Colors { Red = 1, Green = 2, Blue = 4, Yellow = 8 }; public static void Main() { Type weekdays = typeof(Days); Type boiling = typeof(BoilingPoints); Console.WriteLine("The days of the week, and their corresponding values in the Days Enum are:"); foreach ( string s in Enum.GetNames(weekdays) ) Console.WriteLine( "{0,-11}= {1}", s, Enum.Format( weekdays, Enum.Parse(weekdays, s), "d")); Console.WriteLine(); Console.WriteLine("Enums can also be created which have values that represent some meaningful amount."); Console.WriteLine("The BoilingPoints Enum defines the following items, and corresponding values:"); foreach ( string s in Enum.GetNames(boiling) ) Console.WriteLine( "{0,-11}= {1}", s, Enum.Format(boiling, Enum.Parse(boiling, s), "d")); Colors myColors = Colors.Red | Colors.Blue | Colors.Yellow; Console.WriteLine(); Console.WriteLine("myColors holds a combination of colors. Namely: {0}", myColors); } }
Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98, Windows CE, Windows Mobile for Smartphone, Windows Mobile for Pocket PC, Xbox 360, Zune
The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.
Following on from the previous examples, it is often handy to have a helper method for parsing strings to a typed enumeration, including begin able to parse pipe (or indeed any appropriate char) separated values to a flag enumeration. The following helper method (not an extension method) shows this.
public static bool TryParse<TEnum>(string value, out TEnum enumeration) where TEnum : struct, IConvertible
{
enumeration = default(TEnum);
if (string.IsNullOrEmpty(value))
return false;
var type = typeof(TEnum);
if (!type.IsEnum)
return false;
if (value.IndexOf('|') != -1){
var values = value.Split('|');
foreach (var s in values) {
try
{
var temp = (TEnum)Enum.Parse(type, s);
enumeration =
(TEnum)Enum.ToObject(typeof(TEnum),
((IConvertible)temp).ToInt32(null) |
((IConvertible)enumeration).ToInt32(null));
}
catch (ArgumentException) {
return false;
}
}
}
else {
try {
enumeration = (TEnum)Enum.Parse(type, value);
}
catch(ArgumentException) {
return false;
}
}
return true;
}
- 4/17/2009
- Steve Solomon
public static bool IsFlagSet<T>(this T flagToCheck, T enumInstance)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum) return false;
return (((flagToCheck as IConvertible).ToInt32(null) &
(enumInstance as IConvertible).ToInt32(null)) != 0);
}
Which could be called like this:
System.IO.FileAttributes myFlags = (System.IO.FileAttributes.Archive |
System.IO.FileAttributes.Compressed);
//this will test if the Archive flag is set
bool isFlagSet =
System.IO.FileAttributes.Archive.IsFlagSet<System.IO.FileAttributes>(myFlags);
Unfortunately, there is no way to make use of generic type constraints to limit the generic type to enumerations only, however the IsFlagSet method above provides a close approximation by limiting the generic type to value types, and checking the type is an enumeration within the method body.
[Flags]
public enum MyFlagEnum
{
FirstFlag = 1,
SecondFlag = 2,
ThirdFlag = 4,
FourthFlag = 8,
}
You would check to see if a flag is set for a given value like this:
MyFlagEnum flagValue = DetermineFlagValue(); // returns some enumerate value you want to check
if((flagValue & MyFlagEnum.SecondFlag) == MyFlagEnum.SecondFlag)
{
// SecondFlag was set, so handle it
}
This code gets very busy, especially if you have a particularly long name for either the enumeration or its flags (or both!). Fortunately, there is a very simple extension method you can build for your enumerations that will make your code look a lot cleaner:
public static class MyFlagEnumHelper
{
public static bool HasFlag(this MyFlagEnum item, MyFlagEnum query)
{
return ((item & query) == query);
}
}
Then, when you want to check if a flag is set:
MyFlagEnum flagValue = DetermineFlagValue(); // returns some enumerate value you want to check
if(flagValue.HasFlag(MyFlagEnum.SecondFlag))
{
// SecondFlag was set, so handle it
}
Cleaner and easier to understand. Unfortunately the compiler tricks used to create enums mean there's no generic extension method that can be used for all enumerations; you're going to have to include a separate extension method for each flag enumeration you create. Still, that's what snippets are for, right? :)
- 6/25/2008
- RandolphoAtKroll
- 6/25/2008
- RandolphoAtKroll
Some of us have trouble remembering the powers of two all the way up the scale, however, so if you don't want to have to calculate them or are afraid you might miss one, here's another way to build your flags: use the bitshift operator to define your flag values. Recall (or learn) that:
1 << 0 = 1 (decimal) = 00000001 (binary)
1 << 1 = 2 (decimal) = 00000010 (binary)
1 << 2 = 4 (decimal) = 00000100 (binary)
1 << 3 = 8 (decimal) = 00001000 (binary)
See the pattern there? All you have to do is build your enum to use increasing bitshifts of 1 like this (C# example):
[Flags]
public enum MyEnum
{
Default = 0,
Val1 = 1 << 0,
Val2 = 1 << 1,
Val4 = 1 << 2,
Val8 = 1 << 3,
Val2OrVal4 = Val2 | Val4
}
Guaranteed bitwise compatible flags without having to memorize or calculate the powers of two.
- 6/25/2008
- RandolphoAtKroll
- 6/25/2008
- RandolphoAtKroll
Caution: