我有一个接口,看起来像这样:
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)
{
//
}
你不需要把它包装成一个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
获得财产; - 它有一个
T GetResult()
方法。
因此,示例实现将是:
public class FutureAwaiter<T> : INotifyCompletion
{
private readonly IFuture<T> _future;
public bool IsCompleted =>
_future.state == FutureState.Success || _future.state == FutureState.Error;
public FutureAwaiter(IFuture<T> future)
{
_future = future;
}
public void OnCompleted(Action action) => _future.OnComplete(_ => action());
public T GetResult() =>
_future.state == FutureState.Error ? _future.value : throw _future.error;
}
编辑:听从拉法尔的建议,我添加了错误抛出。他建议扩展方法也是正确的,这样您就可以直接await
IFuture<T>
:
public static FutureAwaiter<T> GetAwaiter<T>(this IFuture<T> future) =>
new FutureAwaiter<T>(future);
async Task PrintFuture<T>(IFuture<T> future)
{
Console.WriteLine("Awaiting a future...");
T result = await future;
Console.WriteLine($"Future yielded {result}.");
}
<</div>
div class="one_answers"> 根据未来的实现细节,您可以像这样:
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);
}
}
}