C# 使用Xamarin MessagingCenter调用异步方法时,如何处理异步和等待?
在我的虚拟机中,我有:C# 使用Xamarin MessagingCenter调用异步方法时,如何处理异步和等待?,c#,xamarin,xamarin.forms,C#,Xamarin,Xamarin.forms,在我的虚拟机中,我有: public ICommand FBtnCmd; public PhrasesFrameViewModel(PhrasesFrame phrasesFrame) { FBtnCmd = new Command(() => MessagingCenter.Send<PhrasesFrameViewModel>(this, "FBtn")); } public PhrasesFrame() { InitializeComponent();
public ICommand FBtnCmd;
public PhrasesFrameViewModel(PhrasesFrame phrasesFrame) {
FBtnCmd = new Command(() => MessagingCenter.Send<PhrasesFrameViewModel>(this, "FBtn"));
}
public PhrasesFrame()
{
InitializeComponent();
MessagingCenter.Subscribe<PhrasesFrameViewModel>(this, "FBtn", (s) => this.FBtn());
}
async public Task FBtn()
{
// code here
await Task.Run(() => App.DB.UpdateFavorite(phrase.Favorite, phrase.PhraseId));
// code here
}
公共ICommand FBtnCmd;
公共短语框架视图模型(短语框架短语框架){
FBtnCmd=new命令(()=>MessagingCenter.Send(这是“FBtn”);
}
在后端C#中,我有以下内容:
public ICommand FBtnCmd;
public PhrasesFrameViewModel(PhrasesFrame phrasesFrame) {
FBtnCmd = new Command(() => MessagingCenter.Send<PhrasesFrameViewModel>(this, "FBtn"));
}
public PhrasesFrame()
{
InitializeComponent();
MessagingCenter.Subscribe<PhrasesFrameViewModel>(this, "FBtn", (s) => this.FBtn());
}
async public Task FBtn()
{
// code here
await Task.Run(() => App.DB.UpdateFavorite(phrase.Favorite, phrase.PhraseId));
// code here
}
public短语框架()
{
初始化组件();
订阅(this,“FBtn”,(s)=>this.FBtn());
}
异步公共任务FBtn()
{
//代码在这里
wait Task.Run(()=>App.DB.UpdateFavorite(phrase.Favorite,PhraseId));
//代码在这里
}
它给了我一个警告信息说
由于不等待此调用,因此当前方法的执行
在呼叫完成之前继续。考虑应用“等待”
接线员呼叫呼叫结果
您需要一个事件处理程序来允许使用async Wait。这样可以在委托中避免
async void
,但允许在事件处理程序中使用
public PhrasesFrame() {
InitializeComponent();
fRequested += onfRequested; //subscribe to event
MessagingCenter.Subscribe<PhrasesFrameViewModel>(this, "FBtn", (s) =>
//Raise event
fRequested(s, EventArgs.Empty));
}
private event EventHandler fRequested = delegate { };
private async void onfRequested(object sender, EventArgs args) {
//Await async task
await FBtn();
}
public async Task FBtn() {
// code here
await Task.Run(() => App.DB.UpdateFavorite(phrase.Favorite, phrase.PhraseId));
// code here
}
public短语框架(){
初始化组件();
fRequested+=onfRequested;//订阅事件
MessagingCenter.Subscribe(此“FBtn”,s)=>
//升起事件
频率(s,EventArgs.Empty);
}
private event EventHandler fRequested=委托{};
私有异步void onfRequested(对象发送方、事件args args){
//等待异步任务
等待FBtn();
}
公共异步任务FBtn(){
//代码在这里
wait Task.Run(()=>App.DB.UpdateFavorite(phrase.Favorite,PhraseId));
//代码在这里
}
参考您需要一个事件处理程序来允许使用async Wait。这样可以在委托中避免
async void
,但允许在事件处理程序中使用
public PhrasesFrame() {
InitializeComponent();
fRequested += onfRequested; //subscribe to event
MessagingCenter.Subscribe<PhrasesFrameViewModel>(this, "FBtn", (s) =>
//Raise event
fRequested(s, EventArgs.Empty));
}
private event EventHandler fRequested = delegate { };
private async void onfRequested(object sender, EventArgs args) {
//Await async task
await FBtn();
}
public async Task FBtn() {
// code here
await Task.Run(() => App.DB.UpdateFavorite(phrase.Favorite, phrase.PhraseId));
// code here
}
public短语框架(){
初始化组件();
fRequested+=onfRequested;//订阅事件
MessagingCenter.Subscribe(此“FBtn”,s)=>
//升起事件
频率(s,EventArgs.Empty);
}
private event EventHandler fRequested=委托{};
私有异步void onfRequested(对象发送方、事件args args){
//等待异步任务
等待FBtn();
}
公共异步任务FBtn(){
//代码在这里
wait Task.Run(()=>App.DB.UpdateFavorite(phrase.Favorite,PhraseId));
//代码在这里
}
参考我假设警告在
Subscribe
行。这种情况类似于控件事件处理程序的情况,控件事件处理程序也不是异步的。lambda(s)=>this.FBtn()
基本上是一个委托操作
,其签名的返回类型为void
。因此,如果您在内部启动异步工作,就像这里使用的FBtn
,您将“启动并忘记”,因此操作将在第一个实际异步工作开始执行后立即完成。这种方法可以称为“触发并忘记”,不推荐使用,因为如果在执行FBtn
过程中发生任何异常,该异常将永远不会向上传播,并且您的应用程序可能会进入不一致的状态,而您无法知道。如果FBtn
可能抛出,则应使用try…catch
块:
async (s) => try { await this.FBtn(); } catch { /* handle */ }
我必须在这里使lambda异步无效
,以便等待FBtn
任务
。如果没有wait
,则FBtn
将触发并忘记,并且此处不会发生潜在异常,因为它将位于任务
中,该任务永远不会被等待
,也不会通过GetResult()
或类似方法访问
简言之,你应该总是等待你的任务,避免开火和遗忘。async void
唯一可以使用的地方是事件处理程序和类似的情况,但您应该始终考虑潜在的异常。我假设警告出现在Subscribe
行上。这种情况类似于控件事件处理程序的情况,控件事件处理程序也不是异步的。lambda(s)=>this.FBtn()
基本上是一个委托操作
,其签名的返回类型为void
。因此,如果您在内部启动异步工作,就像这里使用的FBtn
,您将“启动并忘记”,因此操作将在第一个实际异步工作开始执行后立即完成。这种方法可以称为“触发并忘记”,不推荐使用,因为如果在执行FBtn
过程中发生任何异常,该异常将永远不会向上传播,并且您的应用程序可能会进入不一致的状态,而您无法知道。如果FBtn
可能抛出,则应使用try…catch
块:
async (s) => try { await this.FBtn(); } catch { /* handle */ }
我必须在这里使lambda异步无效
,以便等待FBtn
任务
。如果没有wait
,则FBtn
将触发并忘记,并且此处不会发生潜在异常,因为它将位于任务
中,该任务永远不会被等待
,也不会通过GetResult()
或类似方法访问
简言之,你应该总是等待你的任务,避免开火和遗忘。async void
唯一可以使用的地方是事件处理程序和类似的情况,但您应该始终考虑潜在的异常。如果使用了await
,事件处理程序与本例中的Action
或普通async void
方法相比并不是特例,但是await
需要用于任务
异常的展开。@Nkosi那篇文章只是加强了Martin的论点。再次通读该部分,注意Martin在try块中有一个wait
。try/catch示例中没有await
。这是另一种情况-在链接文章中,异常处理不在async void中