Ph0*_*n1x 4 .net c# delegates asynchronous async-await
我正在尝试使这段代码工作:
protected async Task RunIsolated<TServ1, TServ2>(Action<TServ1, TServ2> action)
{
await RunInScope(action, typeof(TServ1), typeof(TServ2));
}
protected async Task<TResult> RunIsolatedForResult<TService, TResult>(Func<TService, TResult> func)
{
return (TResult) await RunInScope(func, typeof(TService));
}
private Task<object> RunInScope(Delegate d, params object[] args)
{
using (var scope = _serviceProvider.CreateScope())
{
object[] parameters = args.Cast<Type>().Select(t => scope.ServiceProvider.GetService(t)).ToArray();
return Task.FromResult(d.DynamicInvoke(parameters));
}
}
Run Code Online (Sandbox Code Playgroud)
这项工作用于同步版本的代码,如下所示:
await RunIsolated<Service>(serv => serv.SaveAsync(item).Wait());
Run Code Online (Sandbox Code Playgroud)
但是对于相同代码的异步版本,不起作用(db操作抛出异常)
await RunIsolated<Service>(async serv => await serv.SaveAsync(item));
Run Code Online (Sandbox Code Playgroud)
是它在某种程度上可能转换异步Action或Func到Delegate并调用它没有松动的异步状态?
您需要创建接受的新重载Func<Task>.现在,你传递的匿名异步功能
await RunIsolated<Service>(async serv => await serv.SaveAsync(item));
Run Code Online (Sandbox Code Playgroud)
被视为Action,这意味着async void基本上是方法,具有所有相应的缺点.相反,你必须做这样的事情(简化为使用基本的Action和Func,根据你的需要调整):
protected Task RunIsolated(Action action) {
return RunInScope(action);
}
protected Task RunIsolated(Func<Task> action) {
return RunInScope(action);
}
protected Task<TResult> RunIsolatedForResult<TResult>(Func<Task<TResult>> action) {
return RunInScopeWithResult<TResult>(action);
}
protected Task<TResult> RunIsolatedForResult<TResult>(Func<TResult> action) {
return RunInScopeWithResult<TResult>(action);
}
private async Task RunInScope(Delegate d, params object[] args) {
// do some stuff
using (var scope = _serviceProvider.CreateScope()) {
object[] parameters = args.Cast<Type>().Select(t => scope.ServiceProvider.GetService(t)).ToArray();
var result = d.DynamicInvoke(parameters);
var resultTask = result as Task;
if (resultTask != null) {
await resultTask;
}
}
}
private async Task<TResult> RunInScopeWithResult<TResult>(Delegate d, params object[] args) {
// do some stuff
using (var scope = _serviceProvider.CreateScope()) {
object[] parameters = args.Cast<Type>().Select(t => scope.ServiceProvider.GetService(t)).ToArray();
var result = d.DynamicInvoke(parameters);
var resultTask = result as Task<TResult>;
if (resultTask != null) {
return await resultTask;
}
return (TResult) result;
}
}
Run Code Online (Sandbox Code Playgroud)