Resharper报“Possible multiple enumeration of IEnumerable”

问题描述:在IEnumerable使用时显示警告

clipboard

分析:如果对IEnumerable多次读取操作,会有因数据源改变导致前后两次枚举项不固定的风险,最突出例子是读取数据库的时候,第二次foreach时恰好数据源发生了改变,那么读取出来的数据和第一次就不一致了。

clipboard[1]

查看测试代码

几乎所有返回类型为 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 ConsoleApplication2
10 {
11     class Program_IEnumerable
12     {
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 Student
54                 {
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

posted @ 2017-08-06 20:04  远方V3  阅读(1032)  评论(0编辑  收藏  举报