Enum.Parse Method
The .NET Framework has an Enum class that contains two Parse methods (http://msdn.microsoft.com/en-us/library/system.enum.parse.aspx https://docs.microsoft.com/en-us/dotnet/api/system.enum.parse). Both of these methods take a string value and attempt to convert it into an Enum value. This works very well, but it has a few shortcomings.
Shortcoming 1: Enum.Parse Returns Object
The first shortcoming is that the return value from Enum.Parse is an Object. This requires the caller to typecast the result of the Enum.Parse method to the appropriate type. For example:
<FlagsAttribute()> _
Enum Colors
Red = 1
Green = 2
Blue = 4
Yellow = 8
End Enum
Dim Choice As Colors
Choice = CType([Enum].Parse(GetType(Colors), "Red"), Colors)
To get around this shortcoming I wrote the following method that will return an enumerated value of the appropriate type.
Public Shared Function ParseEnum(Of EnumType As Structure)( _
ByVal value As String, _
ByVal defaultValue As EnumType) As EnumType
Try
' Attempt to convert string to enumeration using the Parse method
Return CType([Enum].Parse(GetType(EnumType), value, True), EnumType)
Catch ex As ArgumentException
' Return the default value
Return defaultValue
End Try
End Function
When this method is used, no typecasting is required. For example:
Dim Choice As Colors
Choice = ParseEnum("Red", Colors.None)
In order to use this method, the enumeration should have some default value that can be used to indicate the string could not be successfully parsed.
Shortcoming 2: Enum.Parse is unaware of the XmlEnum value
The second shortcoming of the Enum.Parse method is it does not take the XmlEnum value into account when trying to parse the string. For example, if the Colors enumeration were defined as follows:
Public Enum Colors
Invalid
<Xml.Serialization.XmlEnum("R")> _
Red
<Xml.Serialization.XmlEnum("G")> _
Green
<Xml.Serialization.XmlEnum("B")> _
Blue
End Enum
And the following code was executed:
Choice = CType([Enum].Parse(GetType(Colors), "R"), Colors)
A System.ArgumentException("Requested value 'R' was not found.") would be raised to the caller. It would be nice if the Parse method would work for both the ToString and the XmlEnum values, but it only works with the ToString value.
To get around this shortcoming I wrote the following method that will return the correct enumerated value for both the ToString and the XmlEnum values.
Public Shared Function ParseEnum(Of EnumType As Structure)( _
ByVal value As String, _
ByVal defaultValue As EnumType) As EnumType
Dim Result As EnumType
Dim ValueFound As Boolean = False
' Use the standard Parse method
Try
' Attempt to convert string to enumeration value
Result = (CType([Enum].Parse(GetType(EnumType), value, True), EnumType))
ValueFound = True
Catch ex As ArgumentException
ValueFound = False
End Try
' If that does not work, try the XmlEnum values
If ValueFound = False Then
Dim Members() As System.Reflection.FieldInfo
Dim XmlEnumAttributes() As System.Xml.Serialization.XmlEnumAttribute
' Get the list of Enumeration Members
Members = GetType(EnumType).GetFields()
For Each Member As System.Reflection.FieldInfo In Members
' Only examine Enum Members
If Member.IsSpecialName = False AndAlso _
Member.IsLiteral = True Then
' Get the XmlEnum Attributes
XmlEnumAttributes = CType(Member.GetCustomAttributes( _
GetType(System.Xml.Serialization.XmlEnumAttribute), True), _
System.Xml.Serialization.XmlEnumAttribute())
' Check the XmlEnum attribute
If XmlEnumAttributes.Length > 0 AndAlso _
String.Compare(XmlEnumAttributes(0).Name, value, True, _
System.Globalization.CultureInfo.InvariantCulture) = 0 Then
' Found Value
Result = CType(Member.GetValue(Nothing), EnumType)
ValueFound = True
Exit For
End If ' If XmlEnumAttributes.Length > 0 AndAlso
End If ' If Member.IsSpecialName = False AndAlso
Next Member
End If ' If ValueFound = False Then
' If the value still has not been found, use the default value
If ValueFound = False Then
Result = defaultValue
End If
' Return enumeration value
Return Result
End Function
When this method is used, either the ToString or the XmlEnum value can be used. For example, both of the calls below will result in Choice being set to Colors.Red:
Dim Choice As Colors
Choice = ParseEnum("Red", Colors.Invalid)
Choice = ParseEnum("R", Colors.Invalid)
One possible enhancement that could be made to the ParseEnum function is adding support for parsing comma-separated, XmlEnum values for bit field enumerations (e.g. “R, G” would return the value “Colors.Red Or Colors.Green”). See the FlagsAttribute Class help topic (http://msdn.microsoft.com/en-us/library/system.flagsattribute.aspx https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute) for more details on bit field enumerations.
Visual Studio 2008/.NET Framework 3.5 Enhancement
Visual Studio 2008/.NET Framework 3.5 adds extension methods, which allow for methods to be added to existing data types without creating new derived types. This allows us to add a TryParse method, like the one shown below, to the enumerations to provide this functionality.
<System.Runtime.CompilerServices.Extension()> _
Public Function TryParse(Of EnumType As Structure)( _
ByVal enumObject As [Enum], _
ByVal value As String, _
ByRef result As EnumType) As Boolean
Dim ValueFound As Boolean = False
' Use the standard Parse method
Try
' Attempt to convert string to enumeration value
result = (CType([Enum].Parse(GetType(EnumType), value, True), EnumType))
ValueFound = True
Catch ex As ArgumentException
ValueFound = False
End Try
' If that does not work, try the XmlEnum values
If ValueFound = False Then
Dim Members() As System.Reflection.FieldInfo
Dim XmlEnumAttributes() As System.Xml.Serialization.XmlEnumAttribute
' Get the list of Enumeration Members
Members = GetType(EnumType).GetFields()
For Each Member As System.Reflection.FieldInfo In Members
' Only examine Enum Members
If Member.IsSpecialName = False AndAlso _
Member.IsLiteral = True Then
' Get the XmlEnum Attributes
XmlEnumAttributes = CType(Member.GetCustomAttributes( _
GetType(System.Xml.Serialization.XmlEnumAttribute), True), _
System.Xml.Serialization.XmlEnumAttribute())
' Check the XmlEnum attribute
If XmlEnumAttributes.Length > 0 AndAlso _
String.Compare(XmlEnumAttributes(0).Name, value, True, _
System.Globalization.CultureInfo.InvariantCulture) = 0 Then
' Found Value
result = CType(Member.GetValue(Nothing), EnumType)
ValueFound = True
Exit For
End If ' If XmlEnumAttributes.Length > 0 AndAlso
End If ' If Member.IsSpecialName = False AndAlso
Next Member
End If ' If ValueFound = False Then
' Indicate if the value was successfully parsed.
Return ValueFound
End Function
I personally like this solution the best. When this method is used, either the ToString or the XmlEnum value can be used. For example, both of the calls below will result in Choice being set to Colors.Red:
Dim Choice As Colors
Choice.TryParse("Red", Choice)
Choice.TryParse("R", Choice)
Ideally the TryParse method would be a Shared (or static) method, but extension methods cannot be Shared (or static).
No comments:
Post a Comment