C# 仅使用lambda表达式等待
我很难找到正确的语法,以便在lambda表达式(匿名lambda方法)中使用wait。所有示例似乎都使用使用async关键字声明的实际方法。让我描述一下我想要什么:C# 仅使用lambda表达式等待,c#,.net,task-parallel-library,async-await,c#-5.0,C#,.net,Task Parallel Library,Async Await,C# 5.0,我很难找到正确的语法,以便在lambda表达式(匿名lambda方法)中使用wait。所有示例似乎都使用使用async关键字声明的实际方法。让我描述一下我想要什么: ...code in UI thread... Customer cust = null; using (DataContext context = new DataContext()) // I want to run this async { cust = context.Customers.Single(c =>
...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线程将在任务启动后继续。我无法对任务执行等待()
,因为这会阻塞UI线程。只需在任务前面添加wait
。Run()
不会编译。我能想到的最好的办法是:
...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线程。但是我不喜欢并行调用
。调用无论如何,我确信有一种更干净/更好的方法来调用匿名方法,但目前我想不出什么。我还有一个主要的问题,就是我的直觉告诉我,为了实现异步继续(调用数据库查询异步,在此期间不要阻塞UI线程,然后继续执行UI线程上异步调用之后的任何代码),第一行必须以wait…例如: 甚至可能:
...code in UI thread...
Customer cust = await ...(some anonymous lambda method returning Customer)
...continue code in UI thread...
所以我的问题是。如何在不使用任何命名方法的情况下正确编写这段代码,只使用lambda表达式(匿名lambda方法)。您可以使用
任务。运行并等待返回的任务。您只需使用async
关键字标记此方法,并使其返回任务
:
async Task FooAsync()
{
Customer cust = null;
await Task.Run(() =>
{
using (DataContext context = new DataContext())
{
cust = context.Customers.Single(c => c.Id == 1);
}
});
}
现在,如果这是顶级UI事件处理程序,它不能返回任务
,您需要使用async void
。这仅适用于UI事件处理程序
如果无法使方法异步
,并且仍然希望保持操作异步,则可以使用ContinueWith
和TaskScheduler将UI线程操作注册为一个延续。从CurrentSynchronizationContext
确保延续在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());
}
它以什么方式不编译?通常情况下,将await放在Task.Run之前应该不会有任何问题。@erikkallen-“await”运算符只能在异步方法中使用。考虑用“AsiNC”修饰符标记该方法,并将其返回类型改为“任务”。然后执行错误提示所示的信息。我特别想知道如何在不修改外部处理程序/方法的情况下实现“wait”(尽管我在帖子中没有提到这一点,因为我不知道这是唯一的方法)。有时您无法更改方法或处理程序,而我发现,多亏了i3arnon的讨论,在这些情况下,您根本无法使用“wait”。@Marko我认为您不太明白wait
背后的意思。如果你这样做了,约束将非常明显。没有什么能阻止您编写一个从任何地方调用的async void
(甚至async Task
)方法,async
方法的调用方不一定是async
本身。当然,这通常不是一个好主意,但是UI事件处理程序实际上是存在异步void
方法的唯一原因async
不是签名的一部分,它只是对编译器的一个提示-C#团队非常重视维护兼容性。假设我不能用async声明我的方法。我必须遵循void Foo(),但我仍然想在它里面等待,我该怎么做呢?是类似于我提出的Parallel.Invoke的方法,还是如何调用匿名的'async()=>{}方法?编辑:.Single()是不支持异步的简单LINQ2SQL。@Marko如果您的方法不能是async
,则不能使用wait
。您可以启动一个async
操作,并使用任务对其进行阻止。等待
,或者您可以启动它并继续操作,而不必等待它。您可以同步等待、异步等待或根本不等待,没有其他选择。@Marko如果该方法是第三方方法,那么您究竟是如何编写代码作为该方法的实现的?如果您正在为该方法编写代码,可以将其设置为async
@Markoasync
关键字不是签名的一部分async
可以应用于返回任务
、任务
、无效
的任何方法。UI事件处理程序(以及大多数(如果不是所有的话)返回void
,这就是async void
的作用。@Marko如果您只是尝试添加它,您会发现它根本不是问题。
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());
}