使用Xamarin MessagingCenter调用异步方法时,如何处理异步并等待?

时间:2018-08-18 05:55:13

标签: c# xamarin xamarin.forms

在我的VM中,我有这个:

public ICommand FBtnCmd;

public PhrasesFrameViewModel(PhrasesFrame phrasesFrame) {
   FBtnCmd = new Command(() => MessagingCenter.Send<PhrasesFrameViewModel>(this, "FBtn"));
}

在后端C#中,我有这个:

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
}

这是警告消息,告诉我

  

因为不等待此调用,所以执行当前方法   在呼叫完成之前继续。考虑应用“等待”   调用结果的运算符。

2 个答案:

答案 0 :(得分:1)

您将需要一个事件处理程序以允许使用异步等待。这样,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
}

引用Async/Await - Best Practices in Asynchronous Programming

答案 1 :(得分:1)

我认为警告在Subscribe行上。这种情况类似于也不是异步的控制事件处理程序所发生的情况。 lambda (s) => this.FBtn()基本上是委托人Action<PhrasesFrameViewModel>,其签名的返回类型为void。因此,如果您在内部开始异步工作-像在FBtn一样,您将“解雇”,因此该操作将在第一个实际的异步工作开始执行后立即完成。可以将这种方法称为“即发即弃”,因为如果在执行FBtn期间发生任何异常,该异常将永远不会传播,并且如果没有您,您的应用程序可能会进入不一致的状态能够知道。如果FBtn可能会抛出,则应该使用try...catch块:

async (s) => try { await this.FBtn(); } catch { /* handle */ }

我必须在此处制作λasync void,才能await FBtn Task。如果没有awaitFBtn将会被触发并忘记,并且这里不会发生潜在的异常,因为它会在Task内部,永远不会awaited或无法通过{访问{1}}或类似的方法。

简而言之,您应该始终GetResult() await,并避免失火和遗忘。事件处理程序和类似的情况是Task唯一可以接受的地方,但是您应该始终考虑潜在的异常。