我是C#async / await的新手,在尝试使用异步方法时遇到了一些问题。 我有一个集合:
private IList<IContactInfo> _contactInfoList
和异步方法:
public async Task<IList<IContactInfo>> SelectContacts()
{
_contactInfoList = new List<IContactInfo>();
ContactsSelector selector = new ContactsSelector();
selector.ShowPicker();
selector.ContactsSelected += (object sender, ContactsSelectorEventArgs e) =>
{
this._contactInfoList = e.Contacts;
};
return _contactInfoList;
}
联系人选择器是一个弹出式用户控件,允许从手机中选择一些联系人,点击“确定”按钮后会触发ContactsSelected
事件。我需要从事件参数e.Contacts
中获取所选联系人列表,并在上面提到的SelectContacts()
异步方法中返回该列表。问题出在这里:我的方法在_contactInfoList
事件完成工作之前已经返回空列表ContactsSelected
。我知道在这种情况下async / await甚至无关紧要,并且这个问题将存在于通常的方法中,但我只需要使该方法等待事件处理结果。
答案 0 :(得分:4)
您需要做的是将异步编程的事件样式转换为异步编程的任务样式。 TaskCompletionSource
的使用使这相当简单。
public static Task<IList<IContactInfo>> WhenContactsSelected(
this ContactsSelector selector)
{
var tcs = new TaskCompletionSource<IList<IContactInfo>>();
selector.ContactsSelected += (object sender, ContactsSelectorEventArgs e) =>
{
tcs.TrySetResult(e.Contacts);
};
return tcs.Task;
}
既然我们有一个方法可以返回一个我们需要的结果的任务,那么使用它的方法非常简单:
public Task<IList<IContactInfo>> SelectContacts()
{
ContactsSelector selector = new ContactsSelector();
selector.ShowPicker();
return selector.WhenContactsSelected();
}
这里有几点需要注意。首先,我删除了实例字段;这似乎是一个坏主意。如果多次调用SelectContacts
,则会导致两个人争夺该字段。逻辑上,如果您确实需要存储列表,它应该是一个局部变量。接下来,此处没有await
用途,因此该方法不应标记为async
。如果您想await
拨打WhenContactsSelected
,请随时重新添加async
,但截至目前,我认为没有真正的需要。