4

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.

4
  • Why don't you run your reflection code in a ContinueWith call? You'll probably want to call unwrap after ContinueWith to get the Task<object> Commented Dec 2, 2014 at 12:26
  • Is T one to one with cmdName? Commented Dec 2, 2014 at 13:24
  • @fsimonazzi not sure what you mean. Commented Dec 2, 2014 at 14:51
  • @KavehShahbazian No, the return types vary a lot. Commented Dec 2, 2014 at 14:51

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the pointers. Task.Run was the only way I could think to coerce the type at the time. I tweaked it slightly by casting the result, so it still returns object: return (object)(await task);
@Quango: Consider changing the return type to Task<dynamic>. It may simplify your calling code.
5

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; 

1 Comment

Simple when you know how - which I clearly didn't! Many thanks @Lee

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.