I want to convert asynchronous action delegates to asynchronous function delegates that return a specified value. I have come up with an extension method for this:
public static Func<Task<TResult>> Return<TResult>(this Func<Task> asyncAction, TResult result)
{
ArgumentValidate.NotNull(asyncAction, nameof(asyncAction));
return async () =>
{
await asyncAction();
return result;
};
}
However, my extension method is buggy in that exceptions that would have been delivered synchronously from the action delegate now get delivered asynchronously from the function delegate. Concretely:
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
Is there a way of creating this wrapper in such a way that synchronous exceptions continue to delivered synchronously? Is ContinueWith
the way to go?
Update: A concrete example of an asynchronous operation that throws exceptions synchronously:
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);
}
Test:
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