Search code examples
c#asynchronousexpressionsystem.reflection

Async MethodInfo Invoke - cast return type dynamically


I am attempting to call an awaitable method via MethodInfo invoke.
The MethodInfo.Invoke() returns type object that needs to be cast as a Task before I can await it. If I manually cast the return type with a generic parameter of Task, the process works correctly.

However, I have a number of these methods to call that have different return types. How do I handle the return type?

public class Repository
{
    public IEnumerable<Foo> GetListAsync(int criteria)
    {
        return new List<Foo> {new Foo {Bar = "1"}, new Foo {Bar = "2"}};
    }
}

public class Foo
{
    public string Bar { get; set; }
}

public class Precache
{
    public static void RegisterPreCache(Repository instanceObject)
    {

        var preCachedType = typeof (Repository);

        var preCachableMethods =
            preCachedType
                .GetMethods();

        foreach (var cachableMethod in preCachableMethods)
        {
            var resultTask =
                (Task<IEnumerable<Foo>>) cachableMethod.Invoke(instanceObject,
                    new object[]
                    {1});
            Task.Run(async () => await resultTask).Wait();
        }
    }
}

I can get the return type easily from cacheableMethod.ReturnType property. How can I do the cast dynamically? Without the cast, I cannot await the invocation.

I have tried casting simply as Task which of course does not work (EDIT: It does work). I have tried passing all of the parameters into a new generic method, but if I do not specify the generic type must be a Task (where T : Task), I get a compile time error that there is no definition for GetAwaiter.

private static void CallExpression<T>(T returnType, MethodInfo     
    cachableMethod, object instanceObject, object[] parameters) 
{
    var resultTask = (T) cachableMethod.Invoke(instanceObject, parameters);
    Task.Run(async () => await resultTask).Wait();
}

Thank you


Solution

  • With many thanks to Jon Skeet, was able to determine that the issue was the fact that I was making the cast too specific.

    var resultTask = (Task) cachableMethod.Invoke(...)  
    

    allows the MethodInfo invocation to be awaited.