首页 > 代码库 > Resharper报“Possible multiple enumeration of IEnumerable”
Resharper报“Possible multiple enumeration of IEnumerable”
问题描述:在IEnumerable使用时显示警告
分析:如果对IEnumerable多次读取操作,会有因数据源改变导致前后两次枚举项不固定的风险,最突出例子是读取数据库的时候,第二次foreach时恰好数据源发生了改变,那么读取出来的数据和第一次就不一致了。
查看测试代码
几乎所有返回类型为 IEnumerable<T> 或 IOrderedEnumerable<TElement> 的标准查询运算符都以延迟方式执行。如下表我们可以看到where时,返回的IEnumerable是延迟加载的。
标准查询运算符 | Return Type | 立即执行 | 延迟流式执行 | 延迟非流式执行 |
Aggregate | TSource | √ | ||
All<TSource> | Boolean | √ | ||
Any | Boolean | √ | ||
AsEnumerable<TSource> | IEnumerable<T> | √ | ||
Average | 单个数值 | √ | ||
Cast<TResult> | IEnumerable<T> | √ | ||
Concat<TSource> | IEnumerable<T> | √ | ||
Contains | Boolean | √ | ||
Count | Int32 | √ | ||
DefaultIfEmpty | IEnumerable<T> | √ | ||
Distinct | IEnumerable<T> | √ | ||
ElementAt<TSource> | TSource | √ | ||
ElementAtOrDefault<TSource> | TSource | √ | ||
Empty<TResult> | IEnumerable<T> | √ | ||
E√cept | IEnumerable<T> | √ | √ | |
First | TSource | √ | ||
FirstOrDefault | TSource | √ | ||
GroupBy | IEnumerable<T> | √ | ||
GroupJoin | IEnumerable<T> | √ | √ | |
Intersect | IEnumerable<T> | √ | √ | |
Join | IEnumerable<T> | √ | √ | |
Last | TSource | √ | ||
LastOrDefault | TSource | √ | ||
LongCount | Int64 | √ | ||
Ma√ | 单个数值、TSource 或 TResult | √ | ||
Min | 单个数值、TSource 或 TResult | √ | ||
OfType<TResult> | IEnumerable<T> | √ | ||
OrderBy | IOrderedEnumerable<TElement> | √ | ||
OrderByDescending | IOrderedEnumerable<TElement> | √ | ||
Range | IEnumerable<T> | √ | ||
Repeat<TResult> | IEnumerable<T> | √ | ||
Reverse<TSource> | IEnumerable<T> | √ | ||
Select | IEnumerable<T> | √ | ||
SelectMany | IEnumerable<T> | √ | ||
SequenceEqual | Boolean | √ | ||
Single | TSource | √ | ||
SingleOrDefault | TSource | √ | ||
Skip<TSource> | IEnumerable<T> | √ | ||
SkipWhile | IEnumerable<T> | √ | ||
Sum | 单个数值 | √ | ||
Take<TSource> | IEnumerable<T> | √ | ||
TakeWhile | IEnumerable<T> | √ | ||
ThenBy | IOrderedEnumerable<TElement> | √ | ||
ThenByDescending | IOrderedEnumerable<TElement> | √ | ||
ToArray<TSource> | TSource 数组 | √ | ||
ToDictionary | Dictionary<TKey, TValue> | √ | ||
ToList<TSource> | IList<T> | √ | ||
ToLookup | ILookup<TKey, TElement> | √ | ||
Union | IEnumerable<T> | √ | ||
Where | IEnumerable<T> | √ |
解决方案:
多次使用IEnumerable时,最好转换为List或者Array
测试代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 using System.Threading.Tasks; 7 using ConsoleApplication2.EF; 8 9 namespace ConsoleApplication210 {11 class Program_IEnumerable12 {13 static void Main(string[] args)14 {15 // 异步访问数据库16 Task.Run(() =>17 {18 while (true)19 {20 reloadDb();21 }22 });23 24 // 使用死循环不停的读取数据25 int count = 1;26 while (true)27 {28 Console.WriteLine("第{0}读取", count);29 IEnumerable<string> names = getNames();30 31 var allNames = new StringBuilder();32 foreach (var name in names)33 allNames.Append(name + ",");34 Thread.Sleep(500);35 36 var allNames2 = new StringBuilder();37 foreach (var name in names)38 allNames2.Append(name + ",");39 if (allNames2 != allNames)40 Console.WriteLine("数据源发生了改变");41 count++;42 43 Thread.Sleep(1000);44 }45 46 Console.ReadKey();47 }48 49 static void reloadDb()50 {51 using (var infosEntities = new TestEntities())52 {53 infosEntities.Student.Add(new Student54 {55 EnrollmentDate = DateTime.Now,56 FirstMidName = "han",57 LastName = "zhu"58 });59 infosEntities.SaveChanges();60 }61 Thread.Sleep(1000);62 63 using (var infosEntities = new TestEntities())64 {65 var entity = infosEntities.Student.FirstOrDefault(a => a.FirstMidName == "han");66 if (entity != null)67 {68 infosEntities.Student.Remove(entity);69 infosEntities.SaveChanges();70 }71 }72 Thread.Sleep(1000);73 }74 75 static IEnumerable<string> getNames()76 {77 var infosEntities = new TestEntities();78 return infosEntities.Student.Select(a => a.FirstMidName + " " + a.LastName);79 }80 81 }82 83 }
参考资料:
Resharper官方对于这个警告的描述:
https://www.jetbrains.com/help/resharper/PossibleMultipleEnumeration.html
MSDN的解释:
https://msdn.microsoft.com/zh-cn/library/vs/alm/bb882641(v=vs.90)/css
Resharper报“Possible multiple enumeration of IEnumerable”