Enumeration Types and Bit Flags

1. Enumerated Types An
  enumerated type defines a set of "symbolic name/value" pairs.
  For example, the following Color type defines a set of symbols, each of which identifies a color:

copy code
internal enum Color {
While,         // assign 0 
Red,           // assign 1 
Green,         // assign 2 
Blue,          // assign 3 
Orange         // assign 4 
}
copy code

  Benefits of using enum types:  

  1) Enumeration types make programs easier to write, read, and maintain. With enumeration types, symbol names can be used casually in the code, and developers don't need to remember the meaning of every hard-coded one. Also, the code can simply be recompiled without any modification to the source code once the value corresponding to the symbol name changes. In addition, documentation tools and other utilities can display meaningful symbolic names to developers.

  2) Enumeration types are strongly typed.

  In the Microsoft .NET Framework, enumeration types are not just symbols that the compiler cares about, they also have the status of "first-class citizens" in the type system, enabling very powerful operations. Enumeration types are derived directly from System.Enum, which is derived from System.ValueType, which is derived from  System.Object. So, enumeration types are value types that can be represented in both unboxed and boxed forms. However, unlike other value types, enumeration types cannot define any methods, properties, and events. However, adding methods to an enumeration type can be simulated using C#'s "Extension Methods" feature.

  When compiling an enumeration type, the C# compiler converts each symbol into a constant field of the type. For example, the compiler would see the preceding Color enumeration type as the following code:

copy code
internal struct Color : System.Enum
{
  // The following are some public constants that define the symbol and value of Color 
  public  const Color While = (Color) 0 ;
  public  const Color Red = (Color) 1 ;
  public  const Color Green = (Color) 2 ;
  public  const Color Bule = (Color) 3 ;
  public  const Color Orange = (Color) 4 ;

  // The following is a public instance field, which contains the value of a Color variable,
  // Cannot write code to directly reference this instance field 
  public Int32 value__;
}
copy code

  The C# compiler doesn't actually compile this code because it prohibits defining types derived from the special type System.Enum. However,  the inner workings can be understood from the above pseudo-type definition. Simply put, an enumeration type is just a structure that defines a set of constant fields and an instance field. Constant fields are embedded in the assembly's metadata and can be accessed through reflection. This means that all symbols associated with the enum type and their values ​​are available at runtime. It also means that a string symbol can be converted to the corresponding numerical value. These operations are provided through the System.Enum base type, which provides several static and instance methods that can be used to manipulate an instance of an enumeration type, thus avoiding the clutter of having to use reflection. 

bother.  

  Hint: Symbols defined by enum types are constant values. So when the compiler finds that the code refers to a symbol of an enumeration type, it will replace the symbol with a numerical value at compile time, and the code will no longer refer to the enumeration type that defines the symbol. This means that the assembly that defines the enumeration type may not need to be defined at runtime. 

Required at compile time.

  For example, the System.Enum type has a static method of GetUnderlyingType, while the System.Type type has an instance method of GetEnumUnderlyingType.

public  static Type GetUnderlyingType (Type enumType); // Defined in System.Enum 
public Type GetEnumUnderlyingType (Type enumType); // Defined in System.Type

  These methods return the underlying type used to hold the values ​​of an enumeration type. Each enumeration type has an underlying type, which can be byte, sbyte,  short, ushort, int (the most common, and the C# default), uint, long, or ulong. Although these C# primitive types all have FCL types of objects, the C# compiler requires only the primitive type name to be specified in order to simplify its own implementation. If you use an FCL type name (such as Int32), it will report 

wrong.
  The following code demonstrates how to declare an enumeration type with an underlying type of byte (System.Byte):

copy code
inter enum Color :byte {
    While,
    Red,
    Green,
    Blue,
    Orange
}
copy code

  Based on this Color enumeration type, the following code shows the return result of GetUnderlyingType:

// The following code will display "System.Byte" 
Console.WriteLine(Enum.GetUnderlyingType( typeof (Color)));

  The C# compiler treats enumeration types as primitive types. Therefore, many operators (==, !=, <, >, etc.) can be used to manipulate instances of enumeration types. All of these operators actually operate on the value__ instance field inside an instance of an enumeration type. In addition, the C# compiler runs an explicit cast of an instance of an enum type to a non-passed enum type. It is also possible to explicitly cast an instance of an enumeration type to a numeric type.

  You can call the static method GetValue of System.Enum or the instance method GetEnumValue of System.Type to obtain an array, each element of the array corresponds to a symbol name in the enumeration type, and each element contains the value of the symbol name:

public  static Array GetValues(Type enumType); // defined in System.Enum 
public Array GetEnumValues(Type enumType); // defined in System.Type

  This method is used in conjunction with the ToString method to display all symbol names and their corresponding values ​​in the enumeration type, as follows:

copy code
public static void Go() {
    Color[] colors = (Color[])Enum.GetValues(typeof(Color));
    Console.WriteLine("Number of symbols defined: " + colors.Length);
    Console.WriteLine( " Value\tSymbol\n-----\t------ " );
     foreach (Color color in colors) {
  // Display each symbol in decimal and regular format 
    Console.WriteLine( " {0,5:D}\t{0:G} " , color);
    }
}
copy code

  The output produced by the above code is as follows:

Number of symbols defined: 5
Value Symbol
----- ------
0 While
1 Red
2 Green
3 Blue
4 Orange

  There are other enumeration type members, so I won't describe them one by one!

Second, bit flags
  Programmers often have to deal with sets of bit flags. Calling the GetAttributes method of the System.IO.File type returns an instance of the FileAttributes type. The FileAttributes type is an enumeration type whose base type is Int32, each of which reflects an attribute of the file. The FileAttributes type is defined in FCL as follows:

copy code
[Flags]
[Serializable]
[ComVisible (true)]
public enum FileAttributes
{
    Archive = 0x00020,
    Compressed = 0x00800, 
    Device = 0x00040, 
    // Reserved for future use (NOT the w32 value). 
    Directory = 0x00010,
    Encrypted = 0x04000, // NOT the w32 value
    Hidden = 0x00002,
    Normal = 0x00080,
    NotContentIndexed = 0x02000,
    Offline = 0x01000,
    ReadOnly = 0x00001,
    ReparsePoint = 0x00400,
    SparseFile = 0x00200,
    System = 0x00004,
    Temporary = 0x00100,
    #if NET_4_5
    IntegrityStream = 0x8000,
    NoScrubData = 0x20000,
    #endif
}
copy code

  To determine whether a file is hidden, execute the following code:

String file = Assembly.GetEntryAssembly().Location;
FileAttributes attributes = File.GetAttributes(file);
Console.WriteLine("Is {0} hidden? {1}",file,(attributes & FileAttributes.Hidden) !=0);

  The following code demonstrates how to change the attributes of a file to read-only and hidden:

File.SetAttributes (file, FileAttributes.ReadOnly | FileAttribute.Hidden);

  As the FileAttributes type demonstrates, enumerations are often used to represent a set of combinable bit flags. However, while enum types and bit flags are similar, they have different semantics. For example, an enumeration type represents a single numeric value, while a bit identity represents a set of bits, some of which are 1 and some of which are 0.

  When defining an enum type that identifies bit flags, you should of course explicitly assign a numeric value to each symbol. Usually, each symbol has a single bit in the on(1) state. In addition, it is often necessary to define a None symbol with a value of 0. You can also define symbols that represent common bit combinations. In addition, it is strongly recommended to apply the custom attribute type System.Flags.Attribute to the enum type, as shown below

copy code
[Flags] 
public enum Actions {
    Read = 0x0001,
    Write = 0x0002,
    ReadWrite = Actions.Read | Actions.Write,
    Delete = 0x0004,
    Query = 0x0008,
    Sync = 0x0010
}
copy code

  Because Actions is an enumeration type, you can use all the methods described in the previous section when manipulating bit-flag enumeration types.

Actions actions = Actions.Read | Actions.Delete; //0x0005
Console.WriteLine(actions.ToString()); //"Read,Delete"

  When calling ToString, it will convert the value to the corresponding symbol. The current value is 0x0005, which has no corresponding symbol. However, the ToString method detects the presence of the [Flags] attribute on the Actions type, so the ToString method does not now treat the value as a separate value. Instead, treat it as a set of bit flags. Since 0x0005 is composed of 0x0001 and 0x0004, ToString will generate the string "Read, Delete".  If the attribute [Flags] is deleted from the Actions type, the ToString method returns "5".

  Never use the IsDefined method on a bit flag enumeration type for the following reasons:
  1) If you pass a string to the IsDefined method, it will not split the string into individual tokens for lookup, but instead view the entire string , think of it as a larger symbol containing a comma. Since a symbol containing a comma cannot be defined in an enum type, the symbol will never be found.
  2) If you pass a value to the IsDefined method, it checks whether the enumeration type defines a symbol whose corresponding value matches the passed value. Since bit flags cannot be matched so simply, IsDefined usually returns flase.


3. Add methods to enumeration types
  You can now use C#'s extension methods feature to add methods to enumeration type mocks.
  If you want to add some methods to the FileAttributes enumeration type, you can define a static class with extension methods like this:

public static Boolean Set(this FileAttributes flags, FileAttributes testFlags) {
return flags | testFlags;
}

On the surface, it seems that I actually call these methods on the enum type:
FileAttributes fa = FileAttributes.System;
fa = fa.Set(FileAttributes.ReadOnly);

 


Reprint address:

        http://www.cnblogs.com/zxj159/p/3566616.html

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326659794&siteId=291194637