首页 > 代码库 > 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”