在我的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
}
这是警告消息,告诉我
因为不等待此调用,所以执行当前方法 在呼叫完成之前继续。考虑应用“等待” 调用结果的运算符。
答案 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
}
答案 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
。如果没有await
,FBtn
将会被触发并忘记,并且这里不会发生潜在的异常,因为它会在Task
内部,永远不会awaited
或无法通过{访问{1}}或类似的方法。
简而言之,您应该始终GetResult()
await
,并避免失火和遗忘。事件处理程序和类似的情况是Task
唯一可以接受的地方,但是您应该始终考虑潜在的异常。