在调用异步方法时,使用async await返回Task<List<T>>而不是List<T>。

6
我正在尝试理解async await的用法,我研究了一些博客文章,现在我编写了一个测试代码,但它的工作方式并不是我期望的。我有一个方法返回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;
}

然后我写了我的异步方法:
private async Task<List<Employee>> TestEmployeesGetAsync()
{

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

  return result;
}

当我调用这个方法时:
var Result = TestEmployeesGetAsync();

Visual Studio 告诉我它返回 Task<List<T>>,用法是:
List<Employee> result = await TestEmployeesGetAsync();

为什么如果我在调用方法上放置了await,但没有使用async会导致编译错误呢?这当然是因为await应该与async一起使用。有人能告诉我如何调用它,以便我可以得到List<T>而不是Task<List<T>>吗?

1
以下是关于编程的文章:为什么异步方法必须返回Task?异步和等待 - John Woo
@JohnWoo 我怎么能从中获取 List<T> - Ehsan Sajjad
你已经展示了如何获取 List<T>,但你需要在方法上加上 async 关键字,这样才能使用 await - John Woo
我已经创建了异步方法,现在我想调用它并获取“List<T>”。为了调用我的异步方法,我需要再创建另一个方法吗? - Ehsan Sajjad
请查看我的async-await整理上的文章,了解async-await以及如何使用它。 - Paulo Morgado
2个回答

8

如果我在调用方法中加上await,它会给编译器带来错误提示,因为await也必须有async。

编译器需要一些依赖才能理解您正在运行异步方法。这个信号是方法声明中的async修饰符。一旦您将其标记为async,就可以使用await关键字。这就是为什么异步在调用堆栈中"全部传播",因为当您调用一个异步方法并需要等待其结果时,您需要使用async修饰符标记消费方法。

为了使您的方法工作,您需要执行以下操作:

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

作为一种附注,要注意不应该在同步方法上公开异步包装器

你的意思是我不能直接调用它,而必须将其包装在另一个异步方法中吗? - Ehsan Sajjad
99%的时间,这就是你应该调用异步代码的方式。 - Yuval Itzchakov

1
你需要等待由TestEmployeesGetAsync返回的任务结果。你可以使用await异步地获取List<Employee>类型的结果,也可以使用Result属性从任务中获取结果。但是这可能会导致死锁,所以你需要小心处理。
使用async-await方法时,它倾向于在调用链上传递,即等待一个async方法需要在另一个async方法中进行(就像你发现的那样),并且等待该方法需要在另一个async方法中进行,因此async方法在代码库中扩散,直到达到事件处理程序或Main(不能标记为async)。
这种大量使用async方法并不罕见,为了避免这种情况,您可以使用Task.WaitTask.Result等待任务完成,但这些是阻塞方法,可能会导致死锁。这也是一种称为同步超异步的反模式,它破坏了异步工作的目的,因为您最终还是会阻塞等待它完成。
正如@BenVoigt所指出的,有一个例外情况,即当您启动多个异步请求并使用Task.WaitAll阻塞等待所有任务完成时。

它并没有完全打败其目的,因为您仍然可以在等待期间执行多个异步操作。例如,使用Task.WaitAll - Ben Voigt
我会详细解释一下“它倾向于沿着调用链往上走”的意思。如果你不知道这是什么意思,那么理解这个句子会比较困难。 - Eren Ersönmez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接