将回调对象转换为异步Task

时间:2019-07-11 10:26:05

标签: c# asynchronous

我提供的界面如下:

public interface IFuture<T>
{
    FutureState state { get; }
    T value { get; }
    Exception error { get; }
    IFuture<T> OnItem(FutureValueCallback<T> callback);
    IFuture<T> OnSuccess(FutureValueCallback<T> callback);
    IFuture<T> OnError(FutureErrorCallback callback);
    IFuture<T> OnComplete(FutureCallback<T> callback);
}

以下是可用的状态以及代表的代表权限:

public enum FutureState
{
    /// <summary>
    /// The future hasn't begun to resolve a value.
    /// </summary>
    Pending,

    /// <summary>
    /// The future is working on resolving a value.
    /// </summary>
    Processing,

    /// <summary>
    /// The future has a value ready.
    /// </summary>
    Success,

    /// <summary>
    /// The future failed to resolve a value.
    /// </summary>
    Error
}
public delegate void FutureCallback<T>(IFuture<T> future);

public delegate void FutureValueCallback<T>(T value);
public delegate void FutureErrorCallback(Exception error);

我希望能够await继续这个未来。我相信最好的方法是将其转换为Task<T>。但是您将如何精确地做到这一点?签名是这样的:

public static Task<T> ToAwaitable<T>(IFuture<T> future)
{
    //
}

2 个答案:

答案 0 :(得分:3)

您不需要将其包装到Task中,可以使用GetAwaiter()编辑具有适当await方法的任何内容。

public class AwaitableFuture<T>
{
    private readonly IFuture<T> _future;

    public AwaitableFuture(IFuture<T> future)
    {
        _future = future;
    }

    public FutureAwaiter<T> GetAwaiter() => new FutureAwaiter<T>(_future);
}

FutureAwaiter<T>必须是类型T的等待者。对象是T的候补者,如果

  • 它实现INotifyCompletion;
  • 它具有一个bool IsCompleted get属性;
  • 它具有T GetResult()方法。

因此,示例实现为:

public class FutureAwaiter<T> : INotifyCompletion
{
    private readonly IFuture<T> _future;

    public bool IsCompleted => _future.state == FutureState.Completed;

    public FutureAwaiter(IFuture<T> future)
    {
        _future = future;
    }

    public void OnCompleted(Action action) => _future.OnCompleted(x => action);

    public T GetResult() => _future.value;
}

答案 1 :(得分:1)

根据将来的实现细节,您可以像这样:

AsyncResult只是Future的包装,它实现了正确的接口并附加到回调。

internal class AsyncResult<T> : IAsyncResult
{
    private ManualResetEvent _manualResetEvent = new ManualResetEvent(false);

    public object AsyncState => null;

    public WaitHandle AsyncWaitHandle => _manualResetEvent;

    public bool CompletedSynchronously => false;

    public bool IsCompleted { get; private set; }

    public T Result { get; private set; }

    public Exception Error { get; private set; }

    public AsyncResult(IFuture<T> future)
    {
        future.OnSuccess(result =>
            {
                Result = result;
                IsCompleted = true;
                _manualResetEvent.Set();
            });

        future.OnError(() =>
        {
            Error = future.error;
            IsCompleted = true;
            _manualResetEvent.Set();
        });
    }
}

根据需要将Future转换为Task的方法:

public static class FutureExtensions
{
    public static Task<T> ToAsync<T>(this IFuture<T> future)
    {
        var asyncResult = new AsyncResult<T>(future);
        var task = Task.Factory.FromAsync(asyncResult, x =>
        {
            var ar = (AsyncResult<T>)x;
            if (ar.Error != null)
            {
                throw new AggregateException("Task failed.", ar.Error);
            }

            return ar.Result;
        });

        return task;
    }
}

和示例用法:

internal static class Program
{
    public static async Task Main()
    {
        var future = new Future(success: true);

        var result = await future.ToAsync();

        Console.WriteLine(result);

        var future2 = new Future(success: false);

        try
        {
            var result2 = await future2.ToAsync();
        }
        catch (AggregateException e)
        {
            Console.WriteLine(e.InnerException.Message);
        }
    }
}