Quango
Quango

Reputation: 13448

Calling Task<T> methods generically

Related to Casting TResult in Task<TResult> to System.Object. I am building a generic async command execution function for a service.

The method to execute a generic command looks like this:

public async Task<object> ExecuteCommandAsync(string cmdName, CommandData data)

The code uses reflection to find a method on the class that has the given cmdName. Invoking this will return a Type<T> - we don't know the T in advance. However since Task<T> is not covariant, I cannot cast to Task<object>.

At present my solution (as per 21805564) is to call the Result method and encapsulate in a Task.Run, as shown below:

// find the method
MethodInfo cmd = GetMethod(cmdName);
var task = (Task)cmd.Invoke(this, data);
return await Task.Run<object>(() => { return task.GetType().GetProperty("Result").GetValue(task); });

My concern is that doing this negates the value of async: getting the result is now a blocking call so I might as well have used synchronous methods anyway.

Upvotes: 4

Views: 2021

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 456407

Remember that dynamic is available. You can do something like this as long as you're not using Microsoft.Bcl.Async:

public async Task<dynamic> ExecuteCommandAsync(string cmdName, CommandData data)
{
  MethodInfo cmd = GetMethod(cmdName);
  dynamic task = cmd.Invoke(this, data);
  return await task;
}

In particular, I don't recommend using Task.Run because that would waste a thread, and I don't recommend using Task.Result because it will encapsulate any exceptions inside an AggregateException.

Upvotes: 5

Lee
Lee

Reputation: 144126

You can await the task and then reflect on the result once it has completed

public static async Task<object> AwaitResult(Task t)
{
    await t;
    return t.GetType().GetProperty("Result").GetValue(t, null);
} 

Or:

return ((dynamic)t).Result;

Upvotes: 5

Related Questions