0

I'm having one method like the following, where Days is an Enum having values from Sunday to Saturday, Which I'm calling using reflection. I'm having lots of similar methods with different signatures And the input parameters are also dynamic which I'm getting as a JSON.

Public Sub ReflectionMethod(ByVal stringParam As String, ByVal enumParam As Days)
    Console.WriteLine($"Executed:ReflectionMethod | stringParam : {stringParam}; enumParam : {enumParam}")
End Sub

The following code is used to parse the JSON and call the method using reflection.

Dim inputJson As String = "['Sample Input',2]"
Dim lstObjects As List(Of Object) = JsonConvert.DeserializeObject(Of List(Of Object))(inputJson)
Dim method As MethodInfo = consoleObject.GetType.GetMethod("ReflectionMethod")
method.Invoke(consoleObject, lstObjects.ToArray)

Throwing the following error while executing the above code, During debugging noticed that method.Invoke() method is getting failed nothing wrong with the deserialization.

Exception: Object of type 'System.Int64' cannot be converted to type 'VBConsole.Days'.

Please note: This is not the actual code that I'm using, just created a console application for easy debugging, and an answer in C# is also appreciated, That's why tagged it to c#

sujith karivelil
  • 28,671
  • 6
  • 55
  • 88
  • 2
    Well to me, seems pretty clear what the exception is. Your method is returning an int64, and your expected a Days value. Is your real question how to convert the results to the enum? – Hursey Jul 07 '22 at 19:46
  • 1
    `method.Invoke(consoleObject, new { lstObjects[0], Enum.ToObject(typeof(Days), lstObjects[1]) })` – Charlieface Jul 07 '22 at 20:06
  • For the record, there already exists a `DayOfWeek` enumeration, so you probably ought to have used that. If you were going to create your own then it should have been named `Day`, unless you have applied the `Flags` attribute and used powers of 2 for the values. `Enum` names should be singular by default and only pluralised if you specifically want to be able to use composite values. Of course, I don't know for sure that that is not the case here so, if it is, ignore what I said. – John Jul 08 '22 at 02:33

1 Answers1

2

In order to pass your array of JSON values into a method to be invoked by reflection, you must deserialize each JSON value to the required argument type. This can be done as follows:

Public Sub InvokeMethodWithJsonArguments(ByVal consoleObject As Object, ByVal methodName As String, ByVal inputJson As String)
    Dim lstObjects As List(Of JToken) = JsonConvert.DeserializeObject(Of List(Of JToken))(inputJson)    ' Deserialize to an intermediate list of JToken values
    Dim method As MethodInfo = consoleObject.GetType.GetMethod(methodName)
    Dim parameterTypes = method.GetParameters().Select(Function(p) p.ParameterType)                     ' Get the required type of each argument.
    Dim args = lstObjects.Zip(parameterTypes, Function(first, second) first.ToObject(second)).ToArray() ' Deserialize each JToken to the corresponding required type
    method.Invoke(consoleObject, args)                                                                  ' Invoke with the deserialized arguments.
End Sub

Notes:

  • I am assuming you need a solution that does not hardcode the argument types.

  • MethodInfo.GetParameters() returns an array of parameter information matching the signature of the method to be invoked.

  • JToken.ToObject(Type) deserializes a JSON token to a type specified in runtime.

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340