c# - 将异步操作转换为异步函数委托(delegate),保留同步异常传递

标签 c# .net asynchronous async-await task

我想将异步操作委托(delegate)转换为返回指定值的异步函数委托(delegate)。我为此想出了一个扩展方法:

public static Func<Task<TResult>> Return<TResult>(this Func<Task> asyncAction, TResult result)
{
    ArgumentValidate.NotNull(asyncAction, nameof(asyncAction));

    return async () =>
    {
        await asyncAction();
        return result;
    };
}

但是,我的扩展方法存在错误,因为本应从操作委托(delegate)同步传递的异常现在从函数委托(delegate)异步传递。具体来说:

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

最佳答案

好吧,您将无法在初始调用中使用 async。这点很清楚。但是您可以使用调用该函数的同步委托(delegate),然后捕获返回的任务以在异步委托(delegate)中等待它:

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

关于c# - 将异步操作转换为异步函数委托(delegate),保留同步异常传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35633615/

相关文章:

c# - C#中的FNT字体文件

C# 子类返回类型的协方差

c# - 获取所有祖 parent ID 等于 1 的 child

c# - 如何使用 MVP 中的模型填充数据 GridView

testing - Dart 异步测试的奇怪行为

c# - 尝试编写 C# 代码使导弹跟随 Unity 中的玩家

c# - LINQ 程序集位于 Windows XP 中的什么位置?

.net - 当许多相似但截然不同的类需要许多相似但截然不同的依赖项时,如何最好地实现依赖性注入(inject)?

c# - 我是否需要重写我的异步方法/类来实现我想要的功能?

scala - Scala 和 Akka 中的 Future