如何强制任务等待子任务?

时间:2017-02-03 23:28:13

标签: c# multithreading

我必须使用一个API来强制实现其回调接口的类作为身份验证方法的参数。

public class CallBack : ICallBack
{
    public object Response;
    public void OnSuccess(object response)
    {
        Response = response;
    }
    public void OnException(Exception ex) { }
}

身份验证呼叫

public async Task<bool> LoginAsync(string username, string password)
{
    CallBack callback = new CallBack();
    await Task.Factory.StartNew(
        () => userService.Authenticate(username, password, callback),
            TaskCreationOptions.AttachedToParent);
    return callback.Response is User ? true : false;
}

问题是LoginAsync在调用回调之前完成。我希望通过使用Authenticate启动TaskCreationOptions.AttachedToParent调用,它会传播到Authenticate中启动的任何子任务,但事实并非如此。

1 个答案:

答案 0 :(得分:4)

您应该使用TaskCompletionSource对象将基于回调的异步方法包装到一个等待的任务中。

我假设你的ICallBack是这样的:

public interface ICallBack
{
    void OnSuccess(object response);
    void OnException(Exception ex);
}

所以你可以像这样实现LoginAsync:

public async Task<bool> LoginAsync(string username, string password)
{
    var tcs = new TaskCompletionSource<object>();
    ICallBack callback = new CallBackAsync(tcs);
    userService.Authenticate(username, password, callback);
    var result = await tcs.Task;
    return result is User ? true : false;
}

public class CallBackAsync : ICallBack
{
    private TaskCompletionSource<object> _tcs;
    public CallBackAsync(TaskCompletionSource<object> tcs)
    {
        _tcs = tcs;
    }

    public void OnSuccess(object response)
    {
        _tcs.TrySetResult(response);
    }
    public void OnException(Exception ex) {
        _tcs.TrySetException(ex);
    }
}

为了快速解释,当您使用Task.Factory.StartNew()时,在lambda表达式的末尾引发任务的完成。但在你的情况下,这发生在CallBack.OnSuccess调用之前。所以结果没有设定。

TaskCompletionSource类允许您完全控制何时必须完成任务。