|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionIn this article I will discuss some classes I've written to simplify working with enumerations. The primary thrust of these classes is added functionality, but in some cases there are performance improvements as well. EnumDefaultValueAttributeThis class is in response to a shortcoming of the Every variable has a An A simple solution is to use MyEnum x = (MyEnum) System.Enum.GetValues ( typeof(MyEnum) ).GetValue ( 0 ) ;
... but this doesn't give us much control over which value is used. An attribute seems like a good solution to this situation. At first, applying an attribute to the particular member may seem like the right approach... enum MyEnum
{
[EnumDefaultValueAttribute]
Value1 = 1
,
Value2 = 2
...
}
... and indeed it could be done that way, but there's no protection against the attribute being applied to more than one member. Another limitation is if your I chose to have the attribute apply to the [EnumDefaultValueAttribute(MyEnum.Value1)]
enum MyEnum
{
Value1 = 1
,
Value2 = 2
...
}
... but So with this approach we have to use a cast or literal value: [EnumDefaultValueAttribute((int)MyEnum.Value1)]
enum MyEnum
{
Value1 = 1
,
Value2 = 2
...
}
or [EnumDefaultValueAttribute(1)]
enum MyEnum
{
Value1 = 1
,
Value2 = 2
...
}
or [EnumDefaultValueAttribute("Value1")]
enum MyEnum
{
Value1 = 1
,
Value2 = 2
...
}
A limitation of this approach is that there is no compile-time checking of the value (and its type), but that's really no worse than what the GetDefaultValue<T>The bool b ;
MyEnum x ;
b = GetDefaultValue<MyEnum> ( out x ) ;
The return value is a boolean indicating whether or not the value comes from the attribute. If the Accessing attributes requires reflection, which is costly (many have said that but have not provided any numbers to back it up). Here are the results of calling LibEnum.Default<weekday> : Sunday Elapsed= 36630
LibEnum.Default<month> : January Elapsed= 313
LibEnum.Default<weekday> : Sunday Elapsed= 297
(These results are taken from LibEnumMost of the members of GetUnderlyingType<T>System.Type t = LibEnum.GetUnderlyingType<MyEnum>() ;
GetNames<T>string[] names = LibEnum.GetNames<MyEnum>() ;
GetNamestring s = LibEnum.GetName ( MyEnum.Value1 ) ;
Formatstring s = LibEnum.Format ( MyEnum.Value1 , "00" ) ;
GetValues<T>MyEnum[] values = LibEnum.GetValues<MyEnum>() ;
IsDefined<T>
bool b ;
b = LibEnum.IsDefined<MyEnum> ( "Value1" ) ; // Case-sensitive
b = LibEnum.IsDefined<MyEnum> ( "Value1" , false ) ; // Case-sensitive
b = LibEnum.IsDefined<MyEnum> ( "Value1" , true ) ; // Case-insensitive
Parse<T>The built-in way to convert a // Case-sensitive
MyEnum x = (MyEnum) System.Enum.Parse ( typeof(MyEnum) , "Value1" ) ;
// Case-sensitive
MyEnum x = (MyEnum) System.Enum.Parse ( typeof(MyEnum) , "Value1" , false ) ;
// Case-insensitive
MyEnum x = (MyEnum) System.Enum.Parse ( typeof(MyEnum) , "Value1" , true ) ;
With C# 2.0, it is possible to write generic wrapper methods to hide these details, so MyEnum x = LibEnum.Parse<MyEnum> ( "Value1" ) ; // Case-sensitive
MyEnum x = LibEnum.Parse<MyEnum> ( "Value1" , false ) ; // Case-sensitive
MyEnum x = LibEnum.Parse<MyEnum> ( "Value1" , true ) ; // Case-insensitive
TryParse<T>.NET 2.0 also adds MyEnum x ;
LibEnum.TryParse<MyEnum> ( "Value1" , out x ) ; // Case-sensitive
LibEnum.TryParse<MyEnum> ( "Value1" , false , out x ) ; // Case-sensitive
LibEnum.TryParse<MyEnum> ( "Value1" , true , out x ) ; // Case-insensitive
GetDescriptionThere are also times when some text other than the member's name is desired for outputting a user-friendly enum MyEnum
{
[System.ComponentModel.DescriptionAttribute("The first value")]
Value1 = 1
,
[System.ComponentModel.DescriptionAttribute("The second value")]
Value2 = 2
...
}
string s = LibEnum.GetDescription ( MyEnum.Value1 ) ;
GetAlternateText
string s = LibEnum.GetAlternateText
(
MyEnum.Value1
,
typeof(SomeAttribute).GetProperty ( "PropertyName" )
) ;
Performance IssuesThe first group of lines below is from GetDescription1 : Humpday Elapsed= 46588
GetDescription2 : Humpday, TGIF Elapsed= 74064
GetAlternateText1 : Humpday Elapsed= 52950
GetAlternateText2 : Humpday, TGIF Elapsed= 87416
GetDescription1 : Humpday Elapsed= 1106
GetDescription2 : Humpday, TGIF Elapsed= 1146
GetAlternateText1 : Humpday Elapsed= 1644
GetAlternateText2 : Humpday, TGIF Elapsed= 1706
(These results are taken from Default<T>
MyEnum x = LibEnum.Default<MyEnum>() ;
EnumTransmogrifier<T>An application may conceivably parse and output many The The properties The ConstructorsThe simplest way to instantiate an EnumTransmogrifier<MyEnum> MyEnumHelper =
new PIEBALD.Types.EnumTransmogrifier<MyEnum>() ;
This constructor will fill the dictionaries with the values, names, and any In some cases the EnumTransmogrifier<MyEnum> MyEnumHelper = new PIEBALD.Types.EnumTransmogrifier<MyEnum>
(
typeof(SomeAttribute).GetProperty ( "PropertyName" )
) ;
(The If you want parsing to be case-insensitive, you may provide a EnumTransmogrifier<MyEnum> MyEnumHelper = new PIEBALD.Types.EnumTransmogrifier<MyEnum>
(
System.StringComparer.CurrentCultureIgnoreCase
) ;
(The Both EnumTransmogrifier<MyEnum> MyEnumHelper = new PIEBALD.Types.EnumTransmogrifier<MyEnum>
(
typeof(SomeAttribute).GetProperty ( "PropertyName" )
,
System.StringComparer.CurrentCultureIgnoreCase
) ;
Additionally, the constructors allow you to provide a list of aliases to use. This can be handy when the These aliases must be provided as EnumTransmogrifier<MyEnum> MyEnumHelper = new PIEBALD.Types.EnumTransmogrifier<MyEnum>
(
new System.Collections.Generic.KeyValuePair<MyEnum,string>
( MyEnum.Value1 , "One" )
,
new System.Collections.Generic.KeyValuePair<MyEnum,string>
( MyEnum.Value2 , "Two" )
) ;
Providing a EnumTransmogrifier<MyEnum> MyEnumHelper = new PIEBALD.Types.EnumTransmogrifier<MyEnum>
(
new System.Collections.Generic.KeyValuePair<MyEnum,string>
( MyEnum.Value1 , "" )
,
new System.Collections.Generic.KeyValuePair<MyEnum,string>
( MyEnum.Value2 , null )
) ;
Parse
MyEnum x = MyEnumHelper.Parse ( "Value1" ) ;
MyEnum y = MyEnumHelper [ "The first value" ] ;
Note: This TryParse
MyEnum x ;
MyEnumHelper.TryParse ( "Value1" , out x ) ;
MyEnumHelper.TryParse ( "The first value" , out x ) ;
ToString
string s = MyEnumHelper.ToString ( MyEnum.Value1 ) ;
string t = MyEnumHelper [ MyEnum.Value2 ] ;
Clarification on Parse, TryParse, and ToStringThe Alias dictionary contains the member names as well as the aliases, so if the name of a member is passed in to be parsed it will be found in the Alias dictionary. During Parsing, if the During The Demo ProgramsThese demo programs rely on the included Month and Weekday enumerations. (I apologize for any misspellings of non-English month names.) EnumDemo1
EnumDemo2
The output from a sample run (Win XP SP2, .net 2.0, Pentium 4 3GHz, 1GB): LibEnum.Default
The first two lines reflect accessing the The next three lines are parsing operations: Notice that The next six lines are The last four lines were discussed earlier. Using the CodeThe zip file contains:
Once you extract the files to a directory you should be able to execute build.bat to compile the demo programs. (They are console applications.) To use the methods in your own projects, simply add the appropriate files. History
|
||||||||||||||||||||||