views:

454

answers:

5

What I want to do is, based on the type of T do different opperations. Below is a simple example of my problem.

Public Shared Function Example(Of T)() As T
    Dim retval As T
    If TypeOf retval Is String Then
        Dim myString As String = "Hello"
        retval = myString
    ElseIf TypeOf retval Is Integer Then
        Dim myInt As Integer = 101
        retval = myInt
    End If
    Return retval
End Function

I get the error "Value of Type 'String' Cannot be converted to 'T'" Same with the integer part. If I cast either to an object before asigning them to retval it works but I think that would defeat my purpose and be less efficient. Any Ideas? Thanks!

A: 

Do retval = Ctype(Mystring, T) or retVal = Ctype(MyInt, T)

RB Davidson
+3  A: 

With a generic method, T will be of exactly one type each time. Let's say that you have code calling Example(Of Integer). Now, in your mind, replace T with Integer. The resulting method will contain these lines (amongst others).

Dim retval As Integer
    If TypeOf retval Is String Then
        Dim myString As String = "Hello"
        retval = myString
' more code follows '

Assigning a String to an integer like that will never work. Sure, that code will also never execute, since the If-block prevents that, but the code will still not compile. (As a side not, the above code will fail to compile because the TypeOf keyword is restricted to use with reference types, but that is another story)

Typically when creating generic methods, you will want to do the same thing with whatever input you get, but in a type safe manner. If you want to have different behavior for different types of input, you are usually better off by overloading the methods instead.

Fredrik Mörk
True, but it's still possible. All that is necessary is that the 'cast' function returns a generic type. The secret is casting it to object first, and then cast back. See my answer below. Basically T retval = CType(CType(YourGenericVariable, Object), T)
Quandary
A: 
retVal = (T) "Hello World!"
Spencer Ruport
This doesn't work, because CType(YourGenericVariable, T) won't work.
Quandary
A: 

An alternative solution is encapsulate this kind of logic in a class and use VB CallByName function:


    Class Aux(Of T)
        Public Value As T

        Private dicc As Dictionary(Of String, Object)

        Sub New()
            dicc = New Dictionary(Of String, Object)
            dicc.Add("system.string", "hola")
            dicc.Add("system.int32", 15)
            dicc.Add("system.double", 15.0)
        End Sub

        Public Function Test() As T
            Dim typeName As String = GetType(T).ToString.ToLower

            If dicc.ContainsKey(typeName) Then
                CallByName(Me, "Value", CallType.Set, dicc(typeName))
            End If

            Return Value
        End Function

        Protected Overrides Sub Finalize()
            MyBase.Finalize()

            If Not (dicc Is Nothing) Then dicc.Clear()
            dicc = Nothing
        End Sub
    End Class
Alejandro Díaz
A bit of an overkill, ain't it ?
Quandary
A: 

It's probably a bit late, but try this:

    Public Shared Function CAnyType(Of T)(ByRef UTO As Object) As T
        Return CType(UTO, T)
    End Function


    Public Shared Function ExecuteSQLstmtScalar(Of T)(ByVal strSQL As String) As T
        Dim T_ReturnValue As T

        Dim strReturnValue As String = ""


        Dim sqlCMD As Data.SqlClient.SqlCommand = Nothing
        ' Create a connection

        If isDataBaseConnectionOpen() = False Then OpenSQLConnection()


        Try
            System.Threading.Monitor.Enter(m_sqlConnection)
            sqlCMD = New System.Data.SqlClient.SqlCommand(strSQL, m_sqlConnection)
            If sqlCMD.ExecuteScalar() IsNot Nothing Then
                strReturnValue = sqlCMD.ExecuteScalar().ToString
            Else
                strReturnValue = Nothing
            End If

            'MsgBox("Command completed successfully", MsgBoxStyle.OkOnly, "Success !")
        Catch ex As Data.SqlClient.SqlException
            COR.Logging.WriteLogFile("FEHLER", "Ausnahme in cSQL.ExecuteSQLstmtScalar")
            COR.Logging.WriteLogFile("FEHLER", ex.Message)
            COR.Logging.WriteLogFile("FEHLER", "-----------------------------------------------------------------")
            COR.Logging.WriteLogFile("FEHLER", ex.StackTrace.ToString)
            Console.WriteLine(ex.Message.ToString & vbLf & vbLf & ex.StackTrace.ToString, MsgBoxStyle.Critical, "FEHLER ...")
            COR.Logging.WriteLogFile("MELDUNG", "-----------------------------------------------------------------")
        Finally
            m_sqlConnection.Close()
            System.Threading.Monitor.Exit(m_sqlConnection)
            sqlCMD.Dispose()
            sqlCMD = Nothing
        End Try




        Try
            Dim tReturnType As Type = GetType(T)

            If tReturnType Is GetType(String) Then
                Return CAnyType(Of T)(strReturnValue)
            ElseIf tReturnType Is GetType(Boolean) Then
                Dim bReturnValue As Boolean = Boolean.Parse(strReturnValue)
                Return CAnyType(Of T)(bReturnValue)
            ElseIf tReturnType Is GetType(Integer) Then
                Dim iReturnValue As Integer = Integer.Parse(strReturnValue)
                Return CAnyType(Of T)(iReturnValue)
            ElseIf tReturnType Is GetType(Long) Then
                Dim lngReturnValue As Long = Long.Parse(strReturnValue)
                Return CAnyType(Of T)(lngReturnValue)
            Else
                MsgBox("ExecuteSQLstmtScalar(Of T): This type is not yet defined.")
            End If

        Catch ex As Exception

        End Try

        Return Nothing
    End Function
Quandary