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中