Is it true that deferral should be added for any async operation?

廉价感情. 提交于 2019-12-08 18:43:32

问题


According to Likness (p. 164, "Building Windows 8 Apps with C# and XAML"), "When performing asynchronous tasks, you must ask for a deferral."

So if I'm not taking him out of context, this code:

private async Task<System.Collections.Generic.KeyValuePair<string, string>> SelectAContactForASlot()
{
    KeyValuePair<string, string> kvp; 
    var contactPicker = new Windows.ApplicationModel.Contacts.ContactPicker();
    contactPicker.CommitButtonText = "Select";
    var contact = await contactPicker.PickSingleContactAsync();
    if (contact != null)
    {
        kvp = new KeyValuePair<string, string>(contact.Name, contact.Emails[0].ToString());
        return kvp;
    }
    return kvp = new KeyValuePair<string, string>("No Name found", "No email found");
}

...should be this instead:

private async Task<System.Collections.Generic.KeyValuePair<string, string>> SelectAContactForASlot()
{
    var deferral = e.SuspendingOperation.GetDeferral();
    KeyValuePair<string, string> kvp; 
    var contactPicker = new Windows.ApplicationModel.Contacts.ContactPicker();
    contactPicker.CommitButtonText = "Select";
    var contact = await contactPicker.PickSingleContactAsync();
    if (contact != null)
    {
        kvp = new KeyValuePair<string, string>(contact.Name, contact.Emails[0].ToString());
        return kvp;
    }
    return kvp = new KeyValuePair<string, string>("No Name found", "No email found");
    deferral.Complete();
}

Correct?


回答1:


Remember that an async method returns when it hits an await and has to (asynchronously) wait.

You need a deferral when you await an operation from an async void method that must complete before it returns. This kind of "event" is really a command. E.g., "the mouse moved" is just an event - the system doesn't care whether or not you handle the event. But "suspend" is a command - the system assumes that when you return from the command, you are done getting ready to be suspended. In this case, deferrals are necessary to inform the system that even though you're returning, you're not done yet.

Similarly, you need a deferral if you have a background task that has an async implementation of Run. Because when Run returns, your background task is considered done, and you need a way to say you're not really done yet.

You can tell if an event handler supports this by the presence of a GetDeferral method. For example, Suspending supports deferral because SuspendingEventArgs has a SuspendingOperation property which has a GetDeferral method. In the background task scenario (i.e., you have an async void Run), you can call GetDeferral on the IBackgroundTaskInstance passed into Run.

Your example of SelectAContactForASlot returns Task, so it doesn't need the deferral.



来源:https://stackoverflow.com/questions/13421659/is-it-true-that-deferral-should-be-added-for-any-async-operation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!