[笔记]如何将传统的回调函数转换为C#5.0支持的await格式

C#5.0引入了编译器支持的 async 和 await 关键字,这就为开发者提供了使用同步思想写异步代码的方便。

但是有些传统函数仅提供了异步回调实现,如何对其封装,使其可以享受await的便利呢?

举例来说,Windows Phone SDK 提供的 Contacts.SearchAsync() 函数,需要通过Delegate来处理Contacts.SearchAsync事件。

举个Windows Phone 8里面搜索联系人的代码如下:

void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e) {
    try {
        Debug.WriteLine(e.Results.Count());
    }
    catch (Exception ex) {
        Debug.WriteLine(ex.ToString());
    }
}

private void btnSearchContacts_Click(object sender, RoutedEventArgs e) {
    Contacts cons = new Contacts();
    cons.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(Contacts_SearchCompleted);
    cons.SearchAsync("", FilterKind.None, "Contacts Test");
}

不是说这种回调方式不好,而是我认为下面这种使用await的方式调用会更好。

async private Task<IEnumerable<Contact>> SearchContacts(string filter, FilterKind filterKind, Object state) {
    return await Task<IEnumerable<Contact>>.Run(
        () => {
            Debug.WriteLine("SearchContacts begin");

            var signal = new ManualResetEvent(false);
            IEnumerable<Contact> ret = null;

            Contacts cons = new Contacts();
            cons.SearchCompleted += (o, e) => {
                Debug.WriteLine("SearchContacts complete");
                ret = e.Results;
                signal.Set();
            };
            cons.SearchAsync(filter, filterKind, state);
            signal.WaitOne();
            signal.Dispose();
            Debug.WriteLine("SearchContacts end");
            return ret;
        }
        );
}

async private void btnSearchContactsAwait_Click(object sender, RoutedEventArgs e) {
    IEnumerable<Contact> cons = await SearchContacts("", FilterKind.None, "Contacts Test");
    Debug.WriteLine(cons.Count());
}

将代码包装在Task里面,通过ManualResetEvent来控制代码流程,用起来超屌的。

原文地址:https://www.cnblogs.com/journeyonmyway/p/3146388.html