[メモ]従来のコールバック関数をC#5.0でサポートされているawaitフォーマットに変換する方法
4370 ワード
C#5.0はコンパイラがサポートするasyncとawaitキーワードを導入し、開発者に同期思想を用いて非同期コードを書く便利さを提供した.
しかし、一部の従来の関数は非同期コールバック実装のみを提供しており、awaitの利便性を享受できるようにパッケージするにはどうすればいいのでしょうか.
例えば、Windows Phone SDKが提供するContacts.SearchAsync()関数はDelegateでContactsを処理する必要がある.SearchAsyncイベント.
Windows Phone 8で連絡先を検索するコードは以下の通りです.
このようなコールバック方式が悪いというわけではありませんが、次のようなawaitを使う方式で呼び出すともっといいと思います.
コードをTaskにパッケージし、ManualResetEventでコードフローを制御し、超キックアスを使用します.
しかし、一部の従来の関数は非同期コールバック実装のみを提供しており、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でコードフローを制御し、超キックアスを使用します.