1. 程式人生 > >Resharper報“Possible multiple enumeration of IEnumerable”

Resharper報“Possible multiple enumeration of IEnumerable”

lean 固定 isp stringbu read under append 運算符 二次

問題描述:在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 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

Resharper報“Possible multiple enumeration of IEnumerable”