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 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”