异步&;在C#中等待:我是否必须将整个调用链更改为Void方法?
我对C#的整个异步/等待主题是完全陌生的。尽管回答了无数的问题和教程,但我似乎仍然无法理解如何使用async/await。我想要实现的就是wpf应用程序在等待昂贵的方法调用完成时返回到UI上渲染动画-在我下面的示例中,这将是异步&;在C#中等待:我是否必须将整个调用链更改为Void方法?,c#,multithreading,asynchronous,async-await,C#,Multithreading,Asynchronous,Async Await,我对C#的整个异步/等待主题是完全陌生的。尽管回答了无数的问题和教程,但我似乎仍然无法理解如何使用async/await。我想要实现的就是wpf应用程序在等待昂贵的方法调用完成时返回到UI上渲染动画-在我下面的示例中,这将是GetLinesAsync(),或者更具体地说,昂贵的函数(): void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show(GetAMessage()); } string GetAM
GetLinesAsync()
,或者更具体地说,昂贵的函数()
:
void Button_Click(object sender, RoutedEventArgs e) {
MessageBox.Show(GetAMessage());
}
string GetAMessage() {
string ret = "";
foreach(string s in GetLinesAsync().Result)
ret += $"{s}\n";
return ret;
}
async Task<List<string>> GetLinesAsync() {
List<string> ret = new List<string>();
string[] ExpensiveResult = null;
if (await Task.Run(() => expensive_function(ref ExpensiveResult)) == expensive_stat.SUCCESS && ExpensiveResult != null)
{
foreach(string s in ExpensiveResult)
ret.Add(s);
}
void按钮\u单击(对象发送器,路由目标){
Show(GetAMessage());
}
字符串GetAMessage(){
字符串ret=“”;
foreach(GetLinesAsync().Result中的字符串s)
ret+=$“{s}\n”;
返回ret;
}
异步任务GetLinesAsync(){
List ret=新列表();
字符串[]ExpensiveResult=null;
if(wait Task.Run(()=>昂贵的_函数(ref ExpensiveResult))==昂贵的_stat.SUCCESS&&ExpensiveResult!=null)
{
取证(ExpensiveResult中的字符串s)
ret.Add(s);
}
这样编写,应用程序完全冻结,即使昂贵的函数()
不会花那么长时间执行。除此之外,我不确定为什么会发生这种情况,以下是我从阅读关于wait/async的教程和说明中了解到的内容,特别是说您只能等待返回void或Task的方法:
行foreach(GetLinesAsync().Result中的字符串s)
实际上应该说foreach(wait GetLinesAsync().Result中的字符串s)
-但是我必须标记GetMessages()
async,然后我必须用MessageBox.Show(wait GetMessages())替换MessageBox.Show(GetAMessage())
并标记按钮\u单击()
异步
换句话说:等待性将在调用堆栈中逐渐上升,直到它到达一个void方法。好吧,但这不可能,不是吗?如果在其他一些场景中,甚至没有一个敏感的void方法可以上升呢?代码被阻塞的原因是因为您在这里阻塞了它
foreach(string s in GetLinesAsync().Result)
你是说UI线程等待我昂贵的任务完成
让asyn
c自由流动
- 在Windows窗体和WPF中,
/async
具有方便的属性,即在等待的异步操作完成时返回UI线程await
- 对void方法的
支持是专门为支持事件处理程序而添加的。但是,请确保处理异常,因为void将不被观察到async
public async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
MessageBox.Show(await GetAMessage());
}
catch (Exception exception)
{
// log the nelly out of it
// or display message
}
}
public async Task<string> GetAMessage()
{
var list = await GetLinesAsync();
return string.Join("\n", list);
}
public List<string> ExpensiveFunction()
{
// ...
return new List<string>();
}
public async Task<List<string>> GetLinesAsync()
{
var result = Task.Run(() => ExpensiveFunction());
return await result;
}
public async void按钮\u单击(对象发送方,路由目标)
{
尝试
{
Show(等待GetAMessage());
}
捕获(异常)
{
//把耐莉从里面赶走
//或显示消息
}
}
公共异步任务GetAMessage()
{
var list=await GetLinesAsync();
返回字符串。连接(“\n”,列表);
}
公共列表费用函数()
{
// ...
返回新列表();
}
公共异步任务GetLinesAsync()
{
var result=Task.Run(()=>ExpensiveFunction());
返回等待结果;
}
代码被阻塞的原因是因为您在这里阻塞了它
foreach(string s in GetLinesAsync().Result)
你是说UI线程等待我昂贵的任务完成
让asyn
c自由流动
- 在Windows窗体和WPF中,
/async
具有方便的属性,即在等待的异步操作完成时返回UI线程await
- 对void方法的
支持是专门为支持事件处理程序而添加的。但是,请确保处理异常,因为void将不被观察到async
public async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
MessageBox.Show(await GetAMessage());
}
catch (Exception exception)
{
// log the nelly out of it
// or display message
}
}
public async Task<string> GetAMessage()
{
var list = await GetLinesAsync();
return string.Join("\n", list);
}
public List<string> ExpensiveFunction()
{
// ...
return new List<string>();
}
public async Task<List<string>> GetLinesAsync()
{
var result = Task.Run(() => ExpensiveFunction());
return await result;
}
public async void按钮\u单击(对象发送方,路由目标)
{
尝试
{
Show(等待GetAMessage());
}
捕获(异常)
{
//把耐莉从里面赶走
//或显示消息
}
}
公共异步任务GetAMessage()
{
var list=await GetLinesAsync();
返回字符串。连接(“\n”,列表);
}
公共列表费用函数()
{
// ...
返回新列表();
}
公共异步任务GetLinesAsync()
{
var result=Task.Run(()=>ExpensiveFunction());
返回等待结果;
}
换句话说:等待性会在调用堆栈中爬行,直到它到达一个void方法
是的,这就是发生的情况,以及它在现实世界中的工作方式。让它传播,不要阻止它。尽管它并不总是根目录下的一个void
方法。引入了C#7,它允许您拥有一个公共静态异步方法ask Main(字符串[]参数)
方法作为应用程序的入口点。换句话说:等待性将沿着调用堆栈向上爬行,直到它到达一个无效的方法
是的,这就是发生的情况,以及它在现实世界中的工作方式。让它传播,不要阻止它。尽管在根目录下它并不总是一个无效的方法允许您使用公共静态异步任务Main(string[]args)
方法作为应用程序的入口点。这也是Microsoft在其文章中所说的-这对于无效返回事件处理程序(如按钮单击()
)很好。是否有其他方法定义回调,比如说“运行昂贵的函数()
在单独的任务中,继续,完成后运行callback()
“@draconigen如果不想使用异步awat,只需关闭任务或线程,并在要显示消息或更新ui时封送回ui线程。控件。BeginInvoke
或