public static T SyncVer<T>(Func<T> callback)
{
using (new LogContext("new logging context"))
{
try
{
return callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
public static async Task<T> AsyncVer<T>(Func<Task<T>> callback)
{
using (new LogContext("new logging context"))
{
try
{
return await callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
Please consider the code above. You may see most of the code in both functions are the same. I am finding a way to group them up by overloading them into one (or if there a way to take out the similar part of both function) so that I don't need to duplicate the content?
Any help provided will be appreciated. Thanks in advance.
I would try something like this:
public static T SyncVer<T>(Func<T> callback)
{
return AsyncVer(() => Task.FromResult(callback())).GetAwaiter().GetResult();
}
Note that Task.FromResult
will allocate, and GetAwaiter().GetResult()
may dead lock
Personally I would just create two methods and not worry about it.
However, another (and slightly safer) approach is to wrap your callbacks in a ValueTask
. ValueTasks
work best if they execute synchronously, however they have a few subtle limitations and should never be awaited more than once.
The assumption is, this is all about creation an awaitable and non awaitable delegate overload, code reuse, and awaiting the sync version of this call is not a problem for you.
Given
public static async ValueTask<T> SomethingAsync<T>(Func<T> callback)
=> await SomethingAsync(() => new ValueTask<T>(callback()));
public static async ValueTask<T> SomethingAsync<T>(Func<Task<T>> callback)
=> await SomethingAsync(() => new ValueTask<T>(callback()));
public static async ValueTask<T> SomethingAsync<T>(Func<ValueTask<T>> callback)
{
using (new LogContext("new logging context"))
{
try
{
return await callback();
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
Usage
public static string DoSomething()
{
Console.WriteLine("execute sync");
return "sync result";
}
public static async Task<string> DoSomethingAsync()
{
Console.WriteLine("Execute async");
await Task.Delay(100);
return "async result";
}
...
Console.WriteLine(await SomethingAsync(DoSomething));
Console.WriteLine(await SomethingAsync(DoSomethingAsync));
Output
Create
execute sync
Dispose
sync result
Create
Execute async
Dispose
async result
To add some more efficiencies you can elide wrappers
Exmaple
public static ValueTask<T> SomethingAsync<T>(Func<T> callback)
{
try
{
return SomethingAsync(() => new ValueTask<T>(callback()));
}
catch (Exception e)
{
return ValueTask.FromException<T>(e);
}
}
public static ValueTask<T> SomethingAsync<T>(Func<Task<T>> callback)
{
try
{
return SomethingAsync(() => new ValueTask<T>(callback()));
}
catch (Exception e)
{
return ValueTask.FromException<T>(e);
}
}
Note : ValueTask.FromException
is only available for .NET 5.0+
The benefits of this approach:
The downsides are
Note: I personally have never had a need to do this, I would just create the two methods ¯\_(ツ)_/¯
.
Additional resources
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.