ElektroStudios
ElektroStudios

Reputation: 20474

Trying to code a 'String Is Numeric Of Type?' method through reflection

I'm trying to write an overload for a typicall IsNumeric? function, my intention is to accomplish two tasks calling one function (and of course optimizing the code to accomplish the task in the better way and in few lines of code, I don't know if my approach should be the better way but It's what I'm trying):

1st: Determine if the string value is numeric.

2nd: Determine if the numeric value is of the apropiate DataType. (Integer, Long, etc...) Long, etc...)

But I have two problems with this:

1st: The method "TryParse" is not found on the reflection search (I've tried a lot of binding combinations).

2nd: I don't know how to instance the DataType on the method parameters (See: {Value, New T})

Here is my code:

Private Function StringIsNumericOf(Of T)(ByVal Value As String) As Boolean

    Dim Method As MethodInfo =
    GetType(T).GetMethod("TryParse", BindingFlags.Public)

    If Method IsNot Nothing Then
        Return Method.Invoke(Me, BindingFlags.Public, Nothing,
                             New Object() {Value, New T}, 
                             CultureInfo.InvariantCulture)

    Else
        MsgBox("Method not found.")
        Return Nothing

    End If

End Function

And here is an example usage of what I would like to expect:

    ' Expected result: False, it's a Double.
    MsgBox(StringIsNumericOf(Of Long)("50.1D"))

    ' Expected result: False, it's an Int64.
    MsgBox(StringIsNumericOf(Of Integer)("1L"))

    ' Expected result: True
    MsgBox(StringIsNumericOf(Of Long)(CStr(Long.MaxValue)))

UPDATE:

Just a failed intent to solve the 1st problem, this is what I was trying:

    Dim Method As MethodInfo =
    GetType(T).GetMethod("TryParse",
                         BindingFlags.Public Or BindingFlags.Static,
                         Type.DefaultBinder,
                         New Type() {GetType(String), GetType(T)},
                         New ParameterModifier() {})

Upvotes: 1

Views: 71

Answers (2)

ElektroStudios
ElektroStudios

Reputation: 20474

Just this is how looks the final work, thanks to @Jon Egerton answer.

''' <summary>
''' Determines whether an String is a valid numeric of the given type.
''' </summary>
''' <typeparam name="T">Indicates the numeric DataType</typeparam>
''' <param name="Value">Indicates the string value.</param>
''' <returns>
''' <c>true</c> if string is a valid numeric of the given type, <c>false</c> otherwise.
''' </returns>
''' <exception cref="Exception"></exception>
Private Function StringIsNumeric(Of T)(ByVal Value As String) As Boolean

    Const MethodName As String = "TryParse"
    Dim Result As Object = Nothing

    Dim Method As MethodInfo =
    GetType(T).GetMethod(MethodName,
                         BindingFlags.Public Or BindingFlags.Static,
                         Type.DefaultBinder,
                         New Type() {GetType(String), GetType(T).MakeByRefType()},
                         New ParameterModifier() {})

    If Method IsNot Nothing Then
        Return Method.Invoke(Me, BindingFlags.Public Or BindingFlags.Static,
                             Type.DefaultBinder,
                             New Object() {Value, Result},
                             CultureInfo.InvariantCulture)

    Else
        Throw New Exception(String.Format("Method '{0}' not found on '{1}' Type.",
                                          MethodName, GetType(T).Name))
        Return Nothing

    End If

End Function

Upvotes: 0

Jon Egerton
Jon Egerton

Reputation: 41569

First problem: You need to use BindingFlags.Static as well as BindingFlags.Public, as TryParse is a static method on the type.

Second problem, there are two versions of TryParse available. For example for integer there is:

public static bool TryParse( string s, out int result )

and

public static bool TryParse( string s, NumberStyles style, IFormatProvider provider, out int result )

To resolve this you have to pass in an array of types that matches the arguments to the overload you wish to invoke. In this case that is a String, and a ByRef T.

The following should bind the version you want:

    GetType(T).GetMethod("TryParse",
                         BindingFlags.Public Or BindingFlags.Static,
                         Nothing,
                         New Type() {GetType(System.String), GetType(T).MakeByRefType()},
                         Nothing)

Upvotes: 2

Related Questions