我已经找到了答案,但根据许多指南和SO问题,这段代码对我来说仍然是正确的,但它同步运行。
private void CheckConditions()
{
foreach (var obj in myObjects)
{
if (obj.ConditionMet)
{
HandleConditionAsync(obj);
}
}
DoOtherWork();
}
private async void HandleConditionAsync(MyObject obj)
{
// shouldn't control transfer back to CheckConditions() here while we wait for user input?
string userInput = await obj.MessagePromptAsync("hello user");
DoSomeBookkeeping(obj);
}
// (MyObject.cs)
private MessagePrompt messagePrompt; // inherits from UserControl
public async Task<string> MessagePromptAsync(string prompt)
{
return await Task.FromResult<string>(messagePrompt.Prompt(prompt));
}
// (MessagePrompt.cs)
public string Prompt(string prompt)
{
this.UIThread(() => this.SetMessagePrompt(prompt));
userInputAutoResetEvent.WaitOne();
return myResult; // set in a button handler that also sets the AutoResetEvent
}
我打算让CheckConditions()继续快乐地继续,但它仍然停留在MessagePrompt的AutoResetEvent上,尽管我的异步/等待。我唯一能想到的可能是错误的是,由于UserControl的一些限制,它对UI线程引用的使用,或者可能是非异步方法,MessagePrompt的方法可能无法异步运行。堆栈顶部。
答案 0 :(得分:4)
您的代码中没有任何异步内容。您从结果值创建的唯一任务,意味着Prompt()
方法必须完成并返回其结果,然后才能让Task
对象返回等待。该对象已经完成,因此一旦await
等待Task
,该对象就会立即完成。{/ p>
也许你的意思是:
public async Task<string> MessagePromptAsync(string prompt)
{
return await Task.Run(() => messagePrompt.Prompt(prompt));
}
或者(如果你在MessagePromptAsync()
方法中确实没有其他内容):
public Task<string> MessagePromptAsync(string prompt)
{
return Task.Run(() => messagePrompt.Prompt(prompt));
}
请注意,这可能会导致不同的问题,具体取决于DoOtherWork()
和UIThread()
实际执行的操作。如果你的UI线程被DoOtherWork()
绑定,而UIThread()
方法正在包裹Dispatcher.Invoke()
或类似,那么你就会陷入僵局。
如果这不能解决您的问题,请提供可靠地重现问题的好Minimal, Complete, and Verifiable code example。
答案 1 :(得分:1)
您还需要使CheckConditions()
异步,然后等待HandleConditionAsync(MyObject obj)
的调用。 CheckConditions()
在您的示例中同步运行。
private async Task CheckConditionsAsync()
{
foreach (var obj in myObjects)
{
if (obj.ConditionMet)
{
await HandleConditionAsync(obj);
}
}
DoOtherWork();
}
此外,这只是一种最佳实践,异步方法应尽可能始终返回Task。我唯一必须使用async void
是为了与事件处理程序兼容。您可以通过这种方式看到我已更改CheckConditions()
,并且应同样修改HandleConditionAsync(MyObject obj)
。我还更改了方法名称以表示它的异步行为。
如果你需要运行一个同步返回Task
的方法(你不应该这样做,这表明你的设计不正确),你可以用{{1}运行它}}。同样,避免在任何地方都这样做,它首先使得方法异步的目的失败。