await 仅使用 lambda 表达式

await with lambda expressions only

我无法找到正确的语法来使用 await 和 lambda 表达式(匿名 lambda 方法)。所有示例似乎都使用了用 async 关键字声明的实际方法。让我描述一下我想要的:

...code in UI thread...
Customer cust = null;
using (DataContext context = new DataContext()) // I want to run this async
{
   cust = context.Customers.Single(c => c.Id == 1);
}
...continue code in UI thread...

为了在数据库查询期间不阻塞UI线程,我会写:

...code in UI thread...
Customer cust = null;
Task.Run(() => 
{
   using (DataContext context = new DataContext())
   {
      cust = context.Customers.Single(c => c.Id == 1);
   }
});
...continue code in UI thread...

这当然行不通,因为 UI 线程会在任务启动后继续。我不能在 TaskWait(),因为那样会阻塞 UI 线程。简单地在 Task.Run() 前面添加 await 不会编译。我能想到的最好的事情是:

...code in UI thread...
Customer cust = null;
Parallel.Invoke(async () =>
{
   await Task.Run(() => 
   {
      using (DataContext context = new DataContext())
      {
         cust = context.Customers.Single(c => c.Id == 1);
      }
   });
});
...continue code in UI thread...

现在我还没有对此进行测试,所以我不知道这是否真的有效或仍然阻塞 UI 线程。但无论如何我都不喜欢 Parallel.Invoke 调用,我确信有一种调用匿名方法的 cleaner/nicer 方式,但目前我想不出任何办法。我遇到的主要问题是,我的直觉告诉我,为了实现异步继续(调用数据库查询异步,在此期间不要阻塞 UI 线程,然后继续执行异步调用之后的任何代码UI 线程),第一行必须以 await ...
开头 例如:

...code in UI thread...
Customer cust = null;
await ...(whatever follows)
...continue code in UI thread...

或者甚至:

...code in UI thread...
Customer cust = await ...(some anonymous lambda method returning Customer)
...continue code in UI thread...

所以我的问题是。如何在不使用任何命名方法,只使用lambda表达式(匿名lambda方法)的情况下正确编写这段代码。

您可以使用 Task.Runawait returned 任务。您只需要用 async 关键字标记此方法并将其设置为 return a Task:

async Task FooAsync()
{
    Customer cust = null;
    await Task.Run(() => 
    {
       using (DataContext context = new DataContext())
       {
          cust = context.Customers.Single(c => c.Id == 1);
       }
    });
}

现在,如果这是顶级 UI 事件处理程序,它不能 return 和 Task,您需要使用 async void。这仅适用于 UI 事件处理程序。

如果你不能让你的方法 async 并且你仍然想保持操作异步你可以注册 UI 线程操作作为 ContinueWith 和 [= 的延续20=] 以确保继续在 UI 线程上运行:

void Foo()
{
    Customer cust = null;
    var task = Task.Run(() => 
    {
       using (DataContext context = new DataContext())
       {
          cust = context.Customers.Single(c => c.Id == 1);
       }
    });

    task.ContinueWith(antecedent =>
    {
        // ...continue code in UI thread...
    }, TaskScheduler.FromCurrentSynchronizationContext());
}