Logan Logan - 4 months ago 32
Vb.net Question

Vb.net Generic Function cannot convert type T

I have the following function to return a string of hex values to make up a packet of data, but the value can be a byte, UShort, Integer, Single, or a String.

Public Function GetWriteString(ByVal op As Operation, ByVal value As UShort) As String
Dim dataString As String = DATA_CONST & WRITE_CONST & op.ToString(Operation.Accessibility.WRITE) & ToHex(value)
Dim byteCount As String = ToHex(GetByteCount(dataString))
Return headerString & byteCount & CRC_Module.HeaderCRC(headerString & byteCount) & dataString & CRC_Module.DataCRC(dataString)
End Function


I want to make the function a generic function because it is always the same, the only difference is the
ToHex(value)
portion. The
ToHex
Function is an overloaded function for each of the data types specified above, so it will return a different string depending on the value. When I try to make the function generic,

Public Function GetWriteString(Of T)(ByVal op As Operation, ByVal value As T) As String
Dim dataString As String = DATA_CONST & WRITE_CONST & op.ToString(Operation.Accessibility.WRITE) & ToHex(value)
Dim byteCount As String = ToHex(GetByteCount(dataString))
Return headerString & byteCount & CRC_Module.HeaderCRC(headerString & byteCount) & dataString & CRC_Module.DataCRC(dataString)
End Function


it says "Overload resolution failed because no accessible 'ToHex' can be called with these arguments:
Public Function ToHex(hex as Byte) as String: Value of type 'T' cannot be converted to 'Byte'" and so on for each of the overloaded
ToHex
functions. Is there a way to make this function generic, and if so, is this the best way to go about it, or should I create 5 different functions explicitly stating each data type in the parameters for the function?

ToHex Functions:

Public Function ToHex(ByVal characters As String) As String
' Variables
' byteArray - An array of bytes used to hold the characters which were converted to bytes
Dim byteArray As Byte() = defaultEncoding.GetBytes(characters)
' Converts the byte array to a string of hex values
Return BitConverter.ToString(byteArray).Replace("-", "")
End Function

Public Function ToHex(ByVal hex As Byte) As String
Return hex.ToString("X2")
End Function

Public Function ToHex(ByVal word As UShort) As String
Return word.ToString("X4")
End Function

Public Function ToHex(ByVal int As Integer) As String
Return int.ToString("X8")
End Function

''' <summary>
''' Converts a float to a string of hex bytes
''' </summary>
''' <param name="float">A float value to be converted</param>
''' <returns>A string of hex bytes</returns>
Public Function ToHex(ByVal float As Single) As String
' Variables
' byteArray - An array of bytes used to hold the bytes that make up the floating point
Dim byteArray = defaultEncoding.GetBytes(float)
' Reverses the byte array
Array.Reverse(byteArray)
' Converts the byte array to a string of hex values
Return BitConverter.ToString(byteArray).Replace("-", "")
End Function

Answer

You could make your ToHex function take an Object. This is the only way to have a single function across all primitive types, because all the primitive types only share one common base type: object. This doesn't work on DateTime, but you could add a case for it. Note: you can pass anything to this function, so it's not really a good idea to have it in your project. But it should accomplish what you wanted at least.

Option Strict Off

<Runtime.CompilerServices.Extension>
Public Function ToHex(input As Object) As String
    Dim defaultEncoding = System.Text.Encoding.Default
    Dim result As String
    Dim byteArray As Byte()
    If TypeOf (input) Is String Then
        byteArray = defaultEncoding.GetBytes(input)
        result = BitConverter.ToString(byteArray).Replace("-", "")
    Else
        Dim byteCount = System.Runtime.InteropServices.Marshal.SizeOf(input)
        If (TypeOf (input) Is Single) OrElse (TypeOf (input) Is Double) OrElse (TypeOf (input) Is Decimal) Then
            byteArray = BitConverter.GetBytes(input)
            Array.Reverse(byteArray)
            result = BitConverter.ToString(byteArray).Replace("-", "").PadLeft(byteCount * 2, "0")
        Else
            result = CLng(input).ToString("X").PadLeft(byteCount * 2, "0")
        End If
    End If
    Return result
End Function

Testing this:

Console.WriteLine("Single: " & Single.MaxValue.ToHex())
Console.WriteLine("Single: " & 1.0F.ToHex())

Console.WriteLine("Integer: " & Integer.MaxValue.ToHex())
Console.WriteLine("Integer: " & 1I.ToHex())
Console.WriteLine("Integer: " & 1I.ToString("X8"))

Console.WriteLine("UShort: " & UShort.MaxValue.ToHex())
Console.WriteLine("UShort: " & 1US.ToHex())
Console.WriteLine("UShort: " & 1US.ToString("X4"))

Console.WriteLine("String: " & "String".ToHex())

Single: 7F7FFFFF
Single: 3F800000
Integer: 7FFFFFFF
Integer: 00000001
Integer: 00000001
UShort: FFFF
UShort: 0001
UShort: 0001
String: 537472696E67

If you don't want to extend Object, you can remove the <Extension> and just call it like ToHex(Single.MaxValue)

See why we can't accomplish exactly what you want here http://stackoverflow.com/search?q=numeric+generic+C%23