我想将异步操作委托转换为返回指定值的异步函数委托。我想出了一个扩展方法:
public static Func<Task<TResult>> Return<TResult>(this Func<Task> asyncAction, TResult result)
{
ArgumentValidate.NotNull(asyncAction, nameof(asyncAction));
return async () =>
{
await asyncAction();
return result;
};
}
但是,我的扩展方法很麻烦,因为从动作委托同步传递的异常现在从函数委托异步传递。具体地:
Func<Task> asyncAction = () => { throw new InvalidOperationException(); };
var asyncFunc = asyncAction.Return(42);
var task = asyncFunc(); // exception should be thrown here
await task; // but instead gets thrown here
有没有办法以同步异常继续同步传递的方式创建此包装器? ContinueWith
是可行的吗?
更新:同步抛出异常的异步操作的具体示例:
public static Task WriteAllBytesAsync(string filePath, byte[] bytes)
{
if (filePath == null)
throw new ArgumentNullException(filePath, nameof(filePath));
if (bytes == null)
throw new ArgumentNullException(filePath, nameof(bytes));
return WriteAllBytesAsyncInner(filePath, bytes);
}
private static async Task WriteAllBytesAsyncInner(string filePath, byte[] bytes)
{
using (var fileStream = File.OpenWrite(filePath))
await fileStream.WriteAsync(bytes, 0, bytes.Length);
}
测试:
Func<Task> asyncAction = () => WriteAllBytesAsync(null, null);
var asyncFunc = asyncAction.Return(42);
var task = asyncFunc(); // ArgumentNullException should be thrown here
await task; // but instead gets thrown here
答案 0 :(得分:7)
好吧,您将无法在初始通话中使用async
。这很清楚。但是您可以使用调用该函数的同步委托,然后捕获返回的任务以在异步委托中等待它:
public static Func<Task<TResult>> Return<TResult>(this Func<Task> asyncAction, TResult result)
{
ArgumentValidate.NotNull(asyncAction, nameof(asyncAction));
return () =>
{
// Call this synchronously
var task = asyncAction();
// Now create an async delegate for the rest
Func<Task<TResult>> intermediate = async () =>
{
await task;
return result;
};
return intermediate();
};
}
或者,将它重构为两个方法,基本上将异步lambda表达式提取为异步方法:
public static Func<Task<TResult>> Return<TResult>(
this Func<Task> asyncAction, TResult result)
{
ArgumentValidate.NotNull(asyncAction, nameof(asyncAction));
return () =>
{
var task = asyncAction();
return AwaitAndReturn(task, result);
};
}
public static async Func<Task<TResult>> AwaitAndReturn<TResult>(
this Task asyncAction, TResult result)
{
await task;
return result;
}