Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步填充c字典_C#_Linq_For Loop_Async Await_Resharper - Fatal编程技术网

C# 异步填充c字典

C# 异步填充c字典,c#,linq,for-loop,async-await,resharper,C#,Linq,For Loop,Async Await,Resharper,我使用下面的代码循环浏览一个合同列表,并获得每个合同的费率列表。然后将结果存储在字典中 /// <summary> /// Get the Rates for the Job keyed to the id of the Organisation /// </summary> async Task<Dictionary<int, IReadOnlyList<Rate>>> GetRatesAsync(int jobId) { v

我使用下面的代码循环浏览一个合同列表,并获得每个合同的费率列表。然后将结果存储在字典中

/// <summary>
/// Get the Rates for the Job keyed to the id of the Organisation
/// </summary>
async Task<Dictionary<int, IReadOnlyList<Rate>>> GetRatesAsync(int jobId)
{
    var jobContracts = await _contractClient.GetJobContractsByJobAsync(jobId);
    var result = new Dictionary<int, IReadOnlyList<Rate>>();
    foreach (var jobContract in jobContracts)
    {
        result.Add(jobContract.Contract.Organisation.Id, await _contractClient.GetContractRatesByContractAsync(jobContract.Contract.Id));
    }
    return result;
}
然后 错误是wait运算符只能在异步lamba表达式中使用。因此,插入一个异步并将其更改为以下内容:

return jobContracts.ToDictionary(jobContract => jobContract.Contract.Organisation.Id, async jobContract => await _contractClient.GetContractRatesByContractAsync(jobContract.Contract.Id));
然后 错误是现在无法将类型“System.Collections.Generic.Dictionary”隐式转换为“System.Collections.Generic.Dictionary”,它希望我将签名更改为:

async Task<Dictionary<int, Task<IReadOnlyList<Rate>>>> GetContractRatesAsync()
然后
最后一个更改现在可以编译了,但是我所有的调用方法都期望Dictionary任务等待,而不是Dictionary实际上,泛型方法可能非常有趣,所以我将发布一个解决方案。您的初始实现有一个性能问题,如果您愿意,您可以解决,并且您的应用程序域允许这样做

如果您想异步地将项添加到字典中,那么可能需要允许这些异步项并行运行。您希望从一个接受可枚举键和值的方法开始。值应该是生成任务的函数,而不是任务。这样您就不会同时运行所有任务

然后使用信号量控制同时启动多少任务。下面还有一个回退功能,当您希望同时启动所有任务时,可以使用该功能

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace _43909210
{
    public static class EnumerableExtensions
    {
        private static async Task<Dictionary<TKey, TValue>> ToDictionary<TKey,TValue>
            (this IEnumerable<(TKey key, Func<Task<TValue>> valueTask)> source)
        {

            var results = await Task.WhenAll
                ( source.Select( async e => (  key: e.key, value:await e.valueTask() ) ) );

            return results.ToDictionary(v=>v.key, v=>v.value);
        }

        public class ActionDisposable : IDisposable
        {
            private readonly Action _Action;
            public ActionDisposable(Action action) => _Action = action;
            public void Dispose() => _Action();
        }

        public static async Task<IDisposable> Enter(this SemaphoreSlim s)
        {
            await s.WaitAsync();
            return new ActionDisposable( () => s.Release() );
        }


        /// <summary>
        /// Generate a dictionary asynchronously with up to 'n' tasks running in parallel.
        /// If n = 0 then there is no limit set and all tasks are started together.
        /// </summary>
        /// <returns></returns>
        public static async Task<Dictionary<TKey, TValue>> ToDictionaryParallel<TKey,TValue>
            ( this IEnumerable<(TKey key, Func<Task<TValue>> valueTaskFactory)> source
            , int n = 0
            )
        {
            // Delegate to the non limiting case where 
            if (n <= 0)
                return await ToDictionary( source );

            // Set up the parallel limiting semaphore
            using (var pLimit = new SemaphoreSlim( n ))
            {
                var dict = new Dictionary<TKey, TValue>();

                // Local function to start the task and
                // block (asynchronously ) when too many
                // tasks are running
                async Task
                    Run((TKey key, Func<Task<TValue>> valueTask) o)
                {
                    // async block if the parallel limit is reached
                    using (await pLimit.Enter())
                    {
                        dict.Add(o.key, await o.valueTask());
                    }
                }

                // Proceed to start the tasks
                foreach (var task in source.Select( Run ))
                    await task;

                // Wait for all tasks to finish
                await pLimit.WaitAsync();
                return dict;
            }

        }
    }

}

我会坚持使用您的第一种方法——如果您在多个地方需要它,您可以编写自己的扩展方法。您可能希望使用configurewaitfalse。@JonSkeet同意-我暂时不使用它。我只是想确认一下我没有遗漏什么明显的东西。我将在Resharper中将此代码检查的严重性级别从建议更改为提示,以便它停止窃听me@JumpingJezza如果在方法参数=非泛型类型“IEnumerable”不能与类型参数一起使用时出现编译错误,则更好?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace _43909210
{
    public static class EnumerableExtensions
    {
        private static async Task<Dictionary<TKey, TValue>> ToDictionary<TKey,TValue>
            (this IEnumerable<(TKey key, Func<Task<TValue>> valueTask)> source)
        {

            var results = await Task.WhenAll
                ( source.Select( async e => (  key: e.key, value:await e.valueTask() ) ) );

            return results.ToDictionary(v=>v.key, v=>v.value);
        }

        public class ActionDisposable : IDisposable
        {
            private readonly Action _Action;
            public ActionDisposable(Action action) => _Action = action;
            public void Dispose() => _Action();
        }

        public static async Task<IDisposable> Enter(this SemaphoreSlim s)
        {
            await s.WaitAsync();
            return new ActionDisposable( () => s.Release() );
        }


        /// <summary>
        /// Generate a dictionary asynchronously with up to 'n' tasks running in parallel.
        /// If n = 0 then there is no limit set and all tasks are started together.
        /// </summary>
        /// <returns></returns>
        public static async Task<Dictionary<TKey, TValue>> ToDictionaryParallel<TKey,TValue>
            ( this IEnumerable<(TKey key, Func<Task<TValue>> valueTaskFactory)> source
            , int n = 0
            )
        {
            // Delegate to the non limiting case where 
            if (n <= 0)
                return await ToDictionary( source );

            // Set up the parallel limiting semaphore
            using (var pLimit = new SemaphoreSlim( n ))
            {
                var dict = new Dictionary<TKey, TValue>();

                // Local function to start the task and
                // block (asynchronously ) when too many
                // tasks are running
                async Task
                    Run((TKey key, Func<Task<TValue>> valueTask) o)
                {
                    // async block if the parallel limit is reached
                    using (await pLimit.Enter())
                    {
                        dict.Add(o.key, await o.valueTask());
                    }
                }

                // Proceed to start the tasks
                foreach (var task in source.Select( Run ))
                    await task;

                // Wait for all tasks to finish
                await pLimit.WaitAsync();
                return dict;
            }

        }
    }

}