4

我是 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 甚至无关紧要,这个问题在通常的方法中会存在,但我只需要使该方法等待事件处理结果。

4

1 回答 1

4

您需要在这里做的是将异步编程的事件样式转换为异步编程的任务样式。使用 aTaskCompletionSource使这相当简单。

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,但到目前为止,我认为没有真正需要它。

于 2013-11-07T20:47:11.343 回答