简体   繁体   English

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

[英]How to Force Task To Wait for Child Tasks?

I have to use an API that mandates a class that implements its callback interface as a parameter to an authentication method. 我必须使用一个API,该API要求一个类将实现其回调接口的类作为身份验证方法的参数。

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

Authentication Call 认证电话

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;
}

The problem is that LoginAsync finishes before the callback is invoked. 问题在于, LoginAsync在调用回调之前完成。 I hoped that by starting the Authenticate call using TaskCreationOptions.AttachedToParent , it would propagate down to any child tasks started in Authenticate but it does not. 我希望通过使用TaskCreationOptions.AttachedToParent启动Authenticate调用,它可以传播到在Authenticate启动的所有子任务,但不会。

You should use a TaskCompletionSource object to wrap your callback based async method into a awaitable task. 您应该使用TaskCompletionSource对象将基于回调的异步方法包装到可等待的任务中。

I assume your ICallBack is like this : 我假设您的ICallBack是这样的:

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

So you can implement LoginAsync like this : 因此,您可以像这样实现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);
    }
}

For the quick explanation, when you use Task.Factory.StartNew(), the completion of the task is raised at the end of the lambda expression. 为了快速说明,当您使用Task.Factory.StartNew()时,将在lambda表达式的末尾引发任务的完成。 But in your case this occurs before CallBack.OnSuccess call. 但是在您的情况下,这发生在CallBack.OnSuccess调用之前。 So the result is not set. 因此未设置结果。

The TaskCompletionSource class allow you to fully control when the task completion must occurs. TaskCompletionSource类使您可以完全控制何时必须完成任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM