79

I have an ansyc method

public Task<Car> GetCar()
{

}

I can call this method async and await:

 Car car = await GetCar()

How can I invoke the method using MethodInfo.Invoke and await for the result asynchronously.

 MethodInfo method = obj.GetMethod("GetCar");
 method.Invoke( obj, null)
corrego
  • 327
  • 1
  • 7
ajp
  • 1,440
  • 2
  • 13
  • 25

1 Answers1

181

You can invoke it normally and then await the returned task:

Task<Car> result = (Task<Car>)method.Invoke(obj, null);
await result;
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • works like a charm. Thank you – anhtv13 Jul 03 '18 at 10:33
  • It's important to note that `await` blocks the current thread until the `Task` completes (execution is transferred to other threads while waiting). This is asynchronous, but perhaps not in the sense that some might use it (e.g. non-blocking). – Daniel Jun 23 '20 at 14:47
  • 4
    @Daniel: No, `await` does not block the current thread. That's the whole point of `await`. It is truly non-blocking. I have an [async intro](https://blog.stephencleary.com/2012/02/async-and-await.html) and [another blog post](https://blog.stephencleary.com/2013/11/there-is-no-thread.html) that go into more detail. – Stephen Cleary Jun 23 '20 at 16:44
  • @StephenCleary I believe we're arguing semantics, and I'm sure you're correct, but hopefully you can provide the correct terminology. Using `await` halts execution in the current call stack context--I thought that was a "thread", but if it is not, what is it? Certainly the next line of code will not execute until the `await`ed asynchronous operation has completed. – Daniel Jun 23 '20 at 20:30
  • 3
    @Daniel: If it helps, you can think of `async` as changing your method into a state machine, and each `await` is a (potential) point where the state machine method returns. Viewed this way, `await` is just a really fancy syntax for callbacks. So, while it is true that `await` will "pause" the method until the awaitable completes and will lift local variables onto the heap, it's important to note 1) there is no thread waiting for the method to resume (it's a callback, not a thread), and 2) the call stack is not preserved (the callback just executes the next part of the state machine directly). – Stephen Cleary Jun 24 '20 at 00:15
  • @StephenCleary Thanks for responding. I didn't know the call stack wasn't preserved! I'm missing some fundamentals to understand the rest, though. I knew `await` was a callback behind the scenes but hadn't considered the implications. There is necessarily some agent that controls the thread execution context, presumably polling `Task`s for completion when idle to return execution to methods with callbacks/`await`s. Is that agent abstracted entirely out of sight? Now that `void Main()` can be `async`, does that agent exist above the level of user code? – Daniel Jun 25 '20 at 02:33
  • 1
    @Daniel: No, there is no agent, *because* `await` uses callbacks. When the operation completes, the callback *is* the continuation of the method. The `async` keyword tells the compiler to break the method up into chunks (at each `await` point), and then when an `await` pauses, it just wires up the next method chunk as the callback. So there's no monitor or agent or manager for any of this; it's just callbacks all the way down. That's also why the call stack is lost; the chunk is just run directly as a callback, without the original call stack. – Stephen Cleary Jun 25 '20 at 13:39
  • @StephenCleary I understand how the compiler would break up methods as you described, but I don't understand how, with no monitor/agent, a `Task` can be created from an `async` method call and NOT be `await`ed. Without a monitor, how would that `Task` ever complete, since the thread never has a reason to shift execution control to that method? --This is amazing by the way, I'm learning so much from this. – Daniel Jun 25 '20 at 21:23
  • @StephenCleary Unless the answer is simply that the task is queued for a thread in the thread pool and the work is performed in another thread. – Daniel Jun 25 '20 at 21:38
  • 1
    @Daniel: Whatever code completes that task also executes the task's continuations. In the case of I/O, this is a thread pool thread. Again, this is callbacks, and callbacks are just executed on thread pool threads. – Stephen Cleary Jun 25 '20 at 22:04
  • 3
    @StephenCleary I think I follow. Thanks for spending so much time explaining this! Also, I just realized I have your book on concurrency! Clearly I should have finished reading it before having this conversation. :) – Daniel Jun 26 '20 at 13:22
  • I like to think that the call stack is preserved until it reaches an async void method or a call to an async method without `await` – Sasino Jan 11 '21 at 06:38