async await returning Task> instead of List<

2019-06-19 17:53发布

问题:

I am trying to understand the usage of async await and i studied few blog posts and now i have made a testing code but it is not working the way i am expecting it to work.

I have a method which returns List:

private List<Employee> GetEmployees()
{

 IList<Employee> list = new List<Employee>();
 list.Add(new Employee() { Id = 1, Age = 20, Name = "Kavin" });
 list.Add(new Employee() { Id = 2, Age = 30, Name = "Alen" });
 list.Add(new Employee() { Id = 3, Age = 20, Name = "Suresh" });
 list.Add(new Employee() { Id = 4, Age = 30, Name = "Jay" });
 list.Add(new Employee() { Id = 5, Age = 20, Name = "Nanda" });
 list.Add(new Employee() { Id = 5, Age = 20, Name = "Kavin" });
 list.Add(new Employee() { Id = 5, Age = 20, Name = "Kavin" });
 list.Add(new Employee() { Id = 1, Age = 23, Name = "Test" });

 return list;
}

Then i wrote my async method:

private async Task<List<Employee>> TestEmployeesGetAsync()
{

  var result = await Task.Run(() => GetEmployees());

  return result;
}

When i call this method :

var Result = TestEmployeesGetAsync();

The visual studio is telling me that it returns Task<List<T>> and it usage is:

List<Employee> result = await TestEmployeesGetAsync();

Why i need to put await on the calling method if i put await it gives compiler error of course because await should have async as well. Can somebody clear my mind how to call it so that i can get List<T> instead of Task<List<T>>

回答1:

Why i need to put await on the calling method if i put await it gives compiler error of course because await should have async as well.

There are a few dependencies the compiler needs in order to understand you're running an async method. The signal is the async modifier on the method declaration. Once you mark it as async, you can use the await keyword. That is why async propagates "all the way" down the call stack, as when you call one async method and need to await its result, you'll need to mark the consuming method with the async modifier.

In order to make your method work, you'll need to do the following:

public async Task GetEmployeesAsync()
{
   List<Employees> result = await TestEmployeesGetAsync();
}

As a side note, be aware that you should not expose async wrappers over sync methods.



回答2:

You essentially need to wait for the result of the task returned by TestEmployeesGetAsync. You can do that asyncrhonously with await which unwraps the result for you to List<Employee> or you can get the result from the task with the Result property. However that can cause a deadlock so you need to be careful.

With async-await it tends to make its way up the call chain, i.e. awaiting an async method requires you to do that in another async method ( as you have found out), and awaiting that method requires you to be in yet another async method, and so the async methods spread through the code base until you reach an event handler or Main (which cannot be marked async).

This proliferation of async methods is not unusual, and to avoid it, you can wait for the task to complete with Task.Wait and Task.Result but these are blocking method and can cause the aforementioned deadlock. It is also an anti-pattern called sync over async and it defeats the purpose of doing the work asynchronously as you'll end up blocking waiting for it to finish anyway.

As pointed out by @BenVoigt, one exception is when you kick off multiple asynchronous requests and then block waiting for all the tasks to complete with Task.WaitAll.