I have come across a minor glitch in my plans to store FontStyle values in the database. My plan was to store the values as base-2 numbers in the database, eg.
So when I want a bold+italics font, I store the number 3 (this is how the enums work as it is but bold + italics looks like: FontStyle.Bold Or FontStyle.Italics)
My problem is, I can not figure out how to cast these numbers back to the enum so that New Font() will accept them.
Has anyone got any hints or suggestions on this issue?
I wrote this helper:- pretty messy way of doing things... feel free to give me pointers
VB.NET:
[INDENT]'Helper algorythm to convert numerics to fontstyle[/INDENT]
Private Function GetFontStyleFromNumeric(ByVal value As Integer) As FontStyle
Select Case value
Case 0
Return FontStyle.Regular
Case 1
Return FontStyle.Bold
Case 2
Return FontStyle.Italic
Case 3
Return FontStyle.Bold Or FontStyle.Italic
Case 4
Return FontStyle.Underline
Case 5
Return FontStyle.Bold Or FontStyle.Underline
Case 6
Return FontStyle.Italic Or FontStyle.Underline
Case 7
Return FontStyle.Bold Or FontStyle.Italic Or FontStyle.Underline
Case 8
Return FontStyle.Strikeout
Case 9
Return FontStyle.Bold Or FontStyle.Strikeout
Case 10
Return FontStyle.Italic Or FontStyle.Strikeout
Case 11
Return FontStyle.Bold Or FontStyle.Italic Or FontStyle.Strikeout
Case 12
Return FontStyle.Underline Or FontStyle.Strikeout
Case 13
Return FontStyle.Bold Or FontStyle.Underline Or FontStyle.Strikeout
Case 14
Return FontStyle.Italic Or FontStyle.Underline Or FontStyle.Strikeout
Case 15
Return FontStyle.Bold Or FontStyle.Italic Or FontStyle.Underline Or FontStyle.Strikeout
End Select
Return FontStyle.Regular
End Function
TryCast is for reference types only and enumerations are value types. The point of TryCast is that, if the cast can't be performed, a null reference is returned. A value type variable cannot be a null reference (Nothing represents the default value for value types) therefore TryCast has no meaning.
Casting and parsing numbers to enumerations will work even if the number doesn't represent a valid value for that enumeration. If you want to be able to tell the difference between numbers that are valid values for an enumerated type and those that doesn't, here's a method (or two) that will do it:
''' <summary>
''' Tries to parse an input to an enumerated type.
''' </summary>
''' <typeparam name="TEnum">
''' The type to which the input is to be converted.
''' </typeparam>
''' <param name="value">
''' The input to be converted.
''' </param>
''' <param name="result">
''' The converted output.
''' </param>
''' <returns>
''' <b>true</b> if <i>value</i> was successfully converted; otherwise, <b>false</b>.
''' </returns>
''' <exception cref="ArgumentException">
''' <i>result</i> is not an enumerated type.
''' </exception>
''' <remarks>
''' Unlike the Enum.TryParse method, this method will return <b>false</b> if the <i>value</i> can be converted to
''' the underlying numeric type of <i>result</i> but doesn't represent a valid single or combined value of the enumerated type.
''' </remarks>
Private Function TryParseEnum(Of TEnum As Structure)(value As String, _
<Runtime.InteropServices.Out> ByRef result As TEnum) As Boolean
Dim genericType = GetType(TEnum)
'Ensure that the method is only produces a result for enumerated types.
If Not genericType.IsEnum Then
Throw New ArgumentException("Output parameter must be an enumerated type.", "result")
End If
'Determine whether the input can be converted to the enumerated type or its underlying numeric type.
Dim success = [Enum].TryParse(value, result)
If success Then
'Determine whether the input represents a single enumerated value.
success = genericType.IsEnumDefined(result)
If Not success Then
'Determine whether the input represents a combined enumerated value.
'Get all the valid single values for the enumeration in question.
Dim validValues As Array = [Enum].GetValues(genericType)
'Convert the previously obtained result to an Integer.
'NOTE: CObj is required because the compiler only knows that 'result' is a structure,
' so it can't be passed directly to CInt.
Dim residue As Integer = CInt(CObj(result))
'Remove each of the known valid values from the original numeric value to see if there's a residue.
For Each validValue As Integer In validValues
residue = residue And Not validValue
Next
'A residue means a non-valid value.
success = (residue = 0)
End If
End If
If Not success Then
'Clear the result on an unsuccessful conversion.
result = Nothing
End If
Return success
End Function
''' <summary>
''' Tries to parse an input to an enumerated type.
''' </summary>
''' <typeparam name="TEnum">
''' The type to which the input is to be converted.
''' </typeparam>
''' <param name="value">
''' The input to be converted.
''' </param>
''' <param name="result">
''' The converted output.
''' </param>
''' <returns>
''' <b>true</b> if <i>value</i> was successfully converted; otherwise, <b>false</b>.
''' </returns>
''' <exception cref="ArgumentException">
''' <i>result</i> is not an enumerated type.
''' </exception>
''' <remarks>
''' Unlike the Enum.TryParse method, this method will return <b>false</b> if the <i>value</i> can be converted to
''' the underlying numeric type of <i>result</i> but doesn't represent a valid single or combined value of the enumerated type.
''' </remarks>
Private Function TryParseEnum(Of TEnum As Structure)(value As Integer, _
<Runtime.InteropServices.Out> ByRef result As TEnum) As Boolean
Return TryParseEnum(value.ToString(), result)
End Function
That might seem like a lot of code but most of it is comments. Also, once that code is in place, using it is very easy. Here's some sample usage that you can test for yourself:
Dim numbers As Integer() = New Integer() {100, 7, 1}
Dim strings As String() = New String() {"Hello World", _
"Bold", _
"Italic, Underline", _
"OK"}
Dim style As FontStyle
Dim result As DialogResult
For Each number As Integer In numbers
If TryParseEnum(number, style) Then
MessageBox.Show(style.ToString(), number.ToString())
Else
MessageBox.Show("Not a valid FontStyle", number.ToString())
End If
Next
For Each str As String In strings
If TryParseEnum(str, style) Then
MessageBox.Show(style.ToString(), str)
Else
MessageBox.Show("Not a valid FontStyle", str)
End If
Next
For Each number As Integer In numbers
If TryParseEnum(number, result) Then
MessageBox.Show(result.ToString(), number.ToString())
Else
MessageBox.Show("Not a valid DialogResult", number.ToString())
End If
Next
For Each str As String In strings
If TryParseEnum(str, result) Then
MessageBox.Show(result.ToString(), str)
Else
MessageBox.Show("Not a valid DialogResult", str)
End If
Next
Note that the value 100 fails in this case where it would pass using just Enum.TryParse or DirectCast.
Since the source of the value here is a FontStyle value it will be valid to cast back to FontStyle without further ado. It is of course useful to know about the System.Enum class and its functionalities for handling enumerations.
Since the source of the value here is a FontStyle value it will be valid to cast back to FontStyle without further ado. It is of course useful to know about the System.Enum class and its functionalities for handling enumerations.
In theory, yes. Whenever data is stored externally, though, there is always the possibility of its being modified outside the safety of the application that knows and respects what it means. The fact that data shouldn't be modified is never a guarantee that it won't be.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.