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来控制代码流程,用起来超屌的。