如何将异步Func或Action转换为委托并调用它

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将异步Func或Action转换为委托并调用它相关的知识,希望对你有一定的参考价值。

我正在尝试使这段代码工作:

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

这项工作用于同步版本的代码,如下所示:

await RunIsolated<Service>(serv => serv.SaveAsync(item).Wait());

但是对于相同代码的异步版本,不起作用(db操作抛出异常)

await RunIsolated<Service>(async serv => await serv.SaveAsync(item));

是否有可能将异步ActionFunc转换为Delegate并在不失去异步状态的情况下调用它?

答案

您需要创建接受Func<Task>的新重载。现在,你传递的匿名异步功能

await RunIsolated<Service>(async serv => await serv.SaveAsync(item));

被视为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;
    }
}

以上是关于如何将异步Func或Action转换为委托并调用它的主要内容,如果未能解决你的问题,请参考以下文章

C#中Func与Action的理解

为什么我需要将方法强制转换为`Action`或`Func`以在值元组中使用它?

委托代码func和Action的基本用法

C#的异步回调函数

委托delegate,Action,Func,Predicate

C# Action<T;和 Func<T;委托