Paul Cauchon
Paul Cauchon

Reputation: 539

Visual Basic Dynamic Type Conversion and Comparison

I'm attempting to create a function to test the equality of two members of a DataRow object, all of which are initially strings, but need to be converted to their actual data types before comparison. If the data can't be converted to the actual data type, the function should return false. This is the general framework that I'm shooting for.

Private Function compareValues(ByVal row as DataRow, ByVal field as String, ByVal dType as Type) as Boolean
    ' Get the raw values from the DataRow
    Dim raw1 As String = row("t1_" + field).ToString() 
    Dim raw2 As String = row("t2_" + field).ToString() 
    Dim val1, val2 As dtype

    ' Try to convert the raw strings to the target type
    Try
        val1 = CType(raw1, dType) '<--Error here
        val2 = CType(raw2, dType) '<--Error here
    Catch ex As Exception
        Return False ' If either conversion fails, return false
    End Try

    ' Compare the values in their actual types and return false is they don't match
    If (Not val1 = val2) Then
        Return False
    End If
    Return True
End Function

The error I get is: Type 'dType' is not defined.

I've attempted to genericize the function by using the Of clause:

Private Function compareValues(Of dtype)(ByVal row As DataRow, ByVal field As String) As Boolean
    Dim raw1 As String = row("t1_" + field).ToString()
    Dim raw2 As String = row("t2_" + field).ToString()
    Dim val1, val2 As dtype
    Try
        val1 = CTypeDynamic(Of dtype)(raw1)
        val2 = CTypeDynamic(Of dtype)(raw2)
    Catch ex As Exception
        Return False
    End Try
    If (Not val1 = val2) Then '<--Error here
        Return False
    End If
    Return True
End Function

Trying this, however, results in the error: Operator '=' is not defined for types 'dtype' and 'dtype'. Generally speaking, I don't think I'm using the of clause correctly.

Given a datarow, dr, with two fields, t1_size and t2_size, having respective values of "01.92" and "1.92", I'm aiming to call the function like this:

Dim match as Boolean = compareValues(dr, "size", Double) 'evaluates to True

Given the same datarow and fields having respective values of "01.90" and "1.92", the function should be called in the same manner, but return False.

Considering respective values of t1_size and t2_size as "apple" and "01.92", the function should be called in the same manner as the previous examples and still return False.

Resolution/Implementation:

Steven Doggart and Styxxy brought it home with each of their contributions. Please find below the working code:

Private Function compareValues(Of dtype)(row As DataRow, field As String) As Boolean
    Dim val1 As dtype
    Dim val2 As dtype
    Try
        val1 = CType(row("t1_" + field), dtype)
        val2 = CType(row("t2_" + field), dtype)
    Catch ex As Exception
        Return False
    End Try
    If (Not val1.Equals(val2)) Then
        Return False
    End If
    Return True
End Function

Called as follows, assuming you have a DataRow with two columns you wish to compare for equality, "t1_size" and "t2_size", each holding the string representation of a floating point number:

Dim match as Boolean = compareValues(Of Double)(dr, "size")

Upvotes: 4

Views: 2773

Answers (1)

Steven Doggart
Steven Doggart

Reputation: 43743

You have it backwards. When dtype is a Type variable, you should use the CTypeDynamic method, for instance:

Private Function compareValues(row as DataRow, field as String, dType as Type) as Boolean
    ' ...
    val1 = CTypeDynamic(raw1, dtype)
    ' ...
End Function

And when dtype is a generic type, you should use CType, for instance:

Private Function compareValues(Of dtype)(row As DataRow, field As String) As Boolean
    ' ...
    val1 = CType(raw1, dtype)
    ' ...
End Function

However, you probably want to define raw1 and raw2 as Object and set them to the actual field value. I doubt that you really want to convert them to strings just to turn around and convert them back into their proper data type again. For instance:

Dim raw1 As Object = row("t1_" + field)
Dim raw2 As Object = row("t2_" + field)

As Styxxy pointed out, the generic Field extension method was added in version 3.5 of the .NET Framework. It does the conversion for you, so you could skip the "raw" part and do something like this:

Private Function compareValues(Of dtype)(row As DataRow, field As String) As Boolean
    Dim val1 As dtype = row.Field(Of dtype)("t1_" + field)
    ' ...
End Function

Upvotes: 4

Related Questions