Nikhil Goud
Nikhil Goud

Reputation: 584

Use reflection to invoke method

While working with Azure ServiceFabric, we are using StateManager.GetStateAsync method to get values, The same method can be used to get the value in object type like classes.

I'm trying with below Code

var typeObj = Activator.CreateInstance(type);
var method = typeof(IActorStateManager).GetMethod(nameof(IActorStateManager.GetStateAsync));
            var generic = method.MakeGenericMethod(type);
            dynamic task = generic.Invoke(typeObj, new[] { stateName })
            object result = await task;

With this approach, I'm getting the exception.

Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146232829
    HelpLink: null
    InnerException: null
    Message: "Object does not match target type."
    Source: "mscorlib"
    StackTrace: "at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
                at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)  
                at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)   
                at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)"
    TargetSite: {Void CheckConsistency(System.Object)}

Upvotes: 0

Views: 963

Answers (1)

Tewr
Tewr

Reputation: 3853

Most likely, a few things have been confused here. If your code is that what you are actually executing, you are over/misusing the type variable.

Let's decide that type is a concrete ActorStateManager. Then

var typeObj = Activator.CreateInstance(type); // typeobj is now ActorStateManager

The error is probably here:

var generic = method.MakeGenericMethod(type); 
// generic is now StateManager.GetStateAsync<ActorStateManager>

Your intent was not to create StateManager.GetStateAsync<ActorStateManager>, but StateManager.GetStateAsync<bool> or StateManager.GetStateAsync<DateTime>.

Additionally, I GetStateAsync takes an (optional?) cancellationToken as a second argument, better to be explicit when doing reflection.

So here is what you want to do I guess:

    public async Task<object> TryLotsOfTypesAndIgnoreErrors(string stateName)
    {
        var typeObj = Activator.CreateInstance(typeof(ActorStateManager));
        foreach (var typeParam in new[] {typeof(bool), typeof(string)})
        {
            try
            {
                var method = typeof(IActorStateManager).GetMethod(nameof(IActorStateManager.GetStateAsync));
                var generic = method.MakeGenericMethod(typeParam);
                var task = (Task) generic.Invoke(typeObj, new object[] { stateName, CancellationToken.None });
                await task;
                return task.GetType().GetProperty(nameof(Task<object>.Result))?.GetValue(task);
            }
            catch
            {
                // TODO: Catch only exception specific to type mismatch
            }
        }
        return null;
    }

Upvotes: 2

Related Questions