Resolved Using numerical values instead of enums

SnakeRider

New member
Joined
May 22, 2013
Messages
3
Programming Experience
3-5
Hi all,

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.

regular = 0
bold = 1
Italics = 2
strikethrough = 4

etc etc....

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 appreciate your help :)

Cheers!
 
Last edited:
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
 
You don't need all that, just CType/DirectCast the value to type FontStyle.

A tip also if you're working with whole Font objects, you would only need to store one string value, using FontConverter to convert to/from.
 
Thanks mate,

I was originally using TryCast which was failing miserably. DirectCast is the go!
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.
 
Back
Top