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

时间: 2024-08-07 23:21:18

Resharper报“Possible multiple enumeration of IEnumerable”的相关文章

eclipse新建JSP页面报错:Multiple annotations found at this line解决方法

错误提示: Multiple annotations found at this line: - The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path - The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path 错误原因:缺少编译JSP页面

springMVC框架 springmvc-config.xml文件 导入beans、context、mvc命名空间后报错:xml页面开头报错Multiple annotations found at this line

根据网上给出的解决方案,可以解决 1.调出MyEclipse的preference,按照如下图示配置 2.配置好之后,就可以在springmvc-congig.xml文件中引入如下命名空间了 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="

MySQL中出现Multiple primary key defined报错提示之解决办法

创建主键可以有两种方式: create table 表名(字段名 类型,字段名 类型,--primary key(name)); 或者是 create table 表名(字段名 类型 primary key,字段名 类型,--); 但是要注意的是,想要创建复合主键,就不可以用第二种方式.下面列举一个小例子:这里报错Multiple primary key defined,表示定义了多个主键,正确的写法是如下:如果项设置复合主键,复合主键的特点是同时创建.同时删除,所以需要把主键删除,但是这里设置

The main reborn ASP.NET MVC4.0: using CheckBoxListHelper and RadioBoxListHelper

The new Helpers folder in the project, to create the CheckBoxListHelper and RadioBoxListHelper classes. CheckBoxListHelper code using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using

iOS 用instancetype代替id作返回类型有什么好处?

2014-07-07更新:苹果在iOS 8中全面使用instancetype代替id Steven Fisher:只要一个类返回自身的实例,用instancetype就有好处. @interface Foo:NSObject - (id)initWithBar:(NSInteger)bar; // initializer + (id)fooWithBar:(NSInteger)bar; // convenience constructor @end 对于简易构造函数(convenience co

JavaSE:集合总结(Collection,Map)

今天来总结JavaSE部分的集合.首先来从整体来看: 我们主要要学习的内容: Collection: Collection(接口): java.util.Collection |-- List(子接口) : |--ArrayList |--LinkedList |--Vector |-- Set(子接口) : |--AbstracSet(子接口) |--HashSet |--LinkedHashSet |--SortedSet(子接口) |--TreeSet |-- Queue(子接口) : M

SPI Flash

使用了MX25L512的SPI接口的Flash 电路连接图: 总的大小512kb,即64kB,sector的大小为256 Bytes,block的大小为4k Bytes 调试时出现的问题: 1.Flash只能读数据,不能写数据 根源在于Flash的软件写保护没有去掉,这样,写.擦除,甚至写状态寄存器都不能执行. 1)Hardware Protection Hardware Protection Mode(HPM):by using WP# going low to protect the BP0

函数定义、函数声明、函数调用以及extern跨文件的变量引用

1.如果没有定义,只有声明和调用:编译时会报连接错误.undefined reference to `func_in_a'2.如果没有声明,只有定义和调用:编译时一般会报警告,极少数情况下不会报警告.但是最好加上声明.3.如果没有调用,只有定义和声明:编译时一般会报警告(有一个函数没有使用),有时不会报警告.这时候程序执行不会出错,只是你白白的写了几个函数,而没有使用浪费掉了而已. 实验:在一个项目的两个.c文件中,分别定义一个名字相同的函数,结果?编译报错 multiple definitio

mysql数据库修改主键自增及出现的问题

1.创建数据库: create database user ( uid int not null, username varchar(25) not null, password varchar(25) not null. primary key(uid) ); 该语句创建的数据库的主键是user,但是没有设置改字段自增,第一条数据就从0开始.向数据库插入第二条数据而不指定uid的时候就会报错.那如何修改该字段使其自增呢? alert table user modify uid int(4)au