Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Bit Flags

Programmers frequently work with sets of bit flags. When you call the System.IO.File type’s Get­ Attributes method, it returns an instance of a FileAttributes type. A FileAttributes type is an instance of an Int32-based enumerated type, in which each bit reflects a single attribute of the file. The FileAttributes type is defined in the FCL as follows.

 

[Flags, Serializable]

public enum FileAttributes { ReadOnly = 0x00001,

Hidden = 0x00002,

System = 0x00004,

Directory = 0x00010,

Archive = 0x00020,


Device = 0x00040,

Normal = 0x00080,

Temporary = 0x00100,

SparseFile = 0x00200,

ReparsePoint = 0x00400,

Compressed = 0x00800,

Offline = 0x01000, NotContentIndexed = 0x02000, Encrypted = 0x04000, IntegrityStream = 0x08000, NoScrubData = 0x20000

}

 

To determine whether a file is hidden, you would execute code like the following.

 

String file = Assembly.GetEntryAssembly().Location; FileAttributes attributes = File.GetAttributes(file);

Console.WriteLine("Is {0} hidden? {1}", file, (attributes & FileAttributes.Hidden) != 0);

       
   
 
 

 

And here’s code demonstrating how to change a file’s attributes to read-only and hidden.

 

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

 

As the FileAttributes type shows, it’s common to use enumerated types to express the set of bit flags that can be combined. However, although enumerated types and bit flags are similar, they don’t have exactly the same semantics. For example, enumerated types represent single numeric val- ues, and bit flags represent a set of bits, some of which are on, and some of which are off.

When defining an enumerated type that is to be used to identify bit flags, you should, of course, explicitly assign a numeric value to each symbol. Usually, each symbol will have an individual bit turned on. It is also common to see a symbol called None defined with a value of 0, and you can also define symbols that represent commonly used combinations (see the following ReadWrite symbol). It’s also highly recommended that you apply the System.FlagsAttribute custom attribute type to the enumerated type, as shown here:

 

[Flags] // The C# compiler allows either "Flags" or "FlagsAttribute". internal enum Actions {

None = 0,

Read = 0x0001,


Write = 0x0002,

ReadWrite = Actions.Read | Actions.Write, Delete = 0x0004,

Query = 0x0008,

Sync = 0x0010

}

 

Because Actions is an enumerated type, you can use all of the methods described in the previ- ous section when working with bit-flag enumerated types. However, it would be nice if some of those functions behaved a little differently. For example, let’s say you had the following code.

 

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

 

When ToString is called, it attempts to translate the numeric value into its symbolic equivalent.



The numeric value is 0x0005, which has no symbolic equivalent. However, the ToString method detects the existence of the [Flags] attribute on the Actions type, and ToString now treats the numeric value not as a single value but as a set of bit flags. Because the 0x0001 and 0x0004 bits are set, ToString generates the following string: "Read, Delete". If you remove the [Flags] attribute from the Actions type, ToString would return “5”.

I discussed the ToString method in the previous section, and I showed that it offered three ways to format the output: “G” (general), “D” (decimal), and “X” (hex). When you’re formatting an instance of an enumerated type by using the general format, the type is first checked to see if the [Flags] attribute is applied to it. If this attribute is not applied, a symbol matching the numeric value is looked up and returned. If the [Flags] attribute is applied, ToString works like this:

1.The set of numeric values defined by the enumerated type is obtained, and the numbers are

sorted in descending order.

 

2.Each numeric value is bitwise-ANDed with the value in the enum instance, and if the result equals the numeric value, the string associated with the numeric value is appended to the output string, and the bits are considered accounted for and are turned off. This step is repeated until all numeric values have been checked or until the enum instance has all of its bits turned off.

3.If, after all the numeric values have been checked, the enum instance is still not 0, the enum instance has some bits turned on that do not correspond to any defined symbols. In this case, ToString returns the original number in the enum instance as a string.

4.If the enum instance’s original value wasn’t 0, the string with the comma-separated set of symbols is returned.

5.If the enum instance’s original value was 0 and if the enumerated type has a symbol defined

with a corresponding value of 0, the symbol is returned.

 

6.If we reach this step, “0” is returned.


If you prefer, you could define the Actions type without the [Flags] attribute and still get the

correct string by using the “F” format.

 

// [Flags] // Commented out now internal enum Actions {

None = 0

Read = 0x0001,

Write = 0x0002,

ReadWrite = Actions.Read | Actions.Write, Delete = 0x0004,

Query = 0x0008,

Sync = 0x0010

}

 

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

 

If the numeric value has a bit that cannot be mapped to a symbol, the returned string will contain just a decimal number indicating the original numeric value; no symbols will appear in the string.

Note that the symbols you define in your enumerated type don’t have to be pure powers of 2. For example, the Actions type could define a symbol called All with a value of 0x001F. If an instance of the Actions type has a value of 0x001F, formatting the instance will produce a string that contains “All”. The other symbol strings won’t appear.

So far, I’ve discussed how to convert numeric values into a string of flags. It’s also possible to con- vert a string of comma-delimited symbols into a numeric value by calling Enum’s static Parse and TryParse method. Here’s some code demonstrating how to use this method.

 

// Because Query is defined as 8, 'a' is initialized to 8. Actions a = (Actions) Enum.Parse(typeof(Actions), "Query", true); Console.WriteLine(a.ToString()); // "Query"

 

// Because Query and Read are defined, 'a' is initialized to 9. Enum.TryParse<Actions>("Query, Read", false, out a); Console.WriteLine(a.ToString()); // "Read, Query"

 

// Creates an instance of the Actions enum with a value of 28 a = (Actions) Enum.Parse(typeof(Actions), "28", false); Console.WriteLine(a.ToString()); // "Delete, Query, Sync"

 

When Parse and TryParse are called, the following actions are performed internally:

 

1.It removes all whitespace characters from the start and end of the string.

2.If the first character of the string is a digit, plus sign (+), or minus sign (-), the string is assumed to be a number, and an enum instance is returned whose numeric value is equal to the string converted to its numeric equivalent.

3.The passed string is split into a set of tokens (separated by commas), and all white space is trimmed away from each token.


4.Each token string is looked up in the enum type’s defined symbols. If the symbol is not found, Parse throws a System.ArgumentException and TryParse returns false. If the symbol is found, bitwise-OR its numeric value into a running result, and then look up the next token.

5.If all tokens have been sought and found, return the running result.

 

You should never use the IsDefined method with bit flag–enumerated types. It won’t work for

two reasons:

 

■ If you pass a string to IsDefined, it doesn’t split the string into separate tokens to look up; it will attempt to look up the string as through it were one big symbol with commas in it. Because you can’t define an enum with a symbol that has commas in it, the symbol will never be found.

■ If you pass a numeric value to IsDefined, it checks whether the enumerated type defines a single symbol whose numeric value matches the passed-in number. Because this is unlikely for bit flags, IsDefined will usually return false.

 

 


Date: 2016-03-03; view: 717


<== previous page | next page ==>
Nbsp;   Enumerated Types | Nbsp;   Adding Methods to Enumerated Types
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.007 sec.)