LINQifying我的代码是否值得在闭包中访问foreach变量?

让人想起过去的滚石乐队滚石乐队唱片的标题,Resharper比我以往任何时候都更加清晰; 因为我检查了我的代码,它告诉我关于闭包:

1)“循环:

foreach (var item in PlatypiIds) { var query = db.Table().Where(l => l.PlatypusId == item). Where(l=> l.SentTimeUTC >= EarliestToShow). Where(l=> l.SentTimeUTC  l.SentTimeUTC); if (query != null) { foreach (var q in query) { listLocs.Add(q); } } } 

…可以转换为LINQ表达式:

 listLocs.AddRange(from item in PlatypiIds select db.Table().Where(l => l.PlatypusId == item).Where(l => l.SentTimeUTC >= EarliestToShow).Where(l => l.SentTimeUTC  l.SentTimeUTC) into query where query != null from q in query select q);" 

…但是后来Resharper告诉我关于“新的和改进的”代码:“在关闭时访问foreach变量。使用不同版本的编译器编译时可能会有不同的行为”

那么使用不同版本的编译器进行编译的可能性有多大? 我的意思是,从VS2012到VS2010,我不打算倒退,例如… ???

2)在这些方面:

  if (db != null) db.Insert(new PlatypiRequested() 

……这段代码:

  using (var db = new SQLiteConnection(SQLitePath)) { db.CreateTable(); db.RunInTransaction(() => { if (db != null) db.Insert(new PlatypiRequested() { PlatypusId = PlatypusId, PlatypusName = PlatypusName, InvitationSentLocal = invitationSentLocal }); }); } 

… Resharper告诉我,“进入处置关闭”

这是什么意思,我应该怎么做呢?

这里有两个不同的问题,一个是LINQ vs foreach,另一个是不同的情况。

关于ReSharper告诉你“在关闭时访问foreach变量……”代码是LINQified – 我只是从不抓住机会,把它留作foreach循环。 在大多数情况下,它也更具可读性和可维护性,实际上,缩短代码并不是什么大问题。

关于第二种情况 – 您需要丢失using语句,因为db对象将很快被丢弃。 你应该关闭并将它放在RunInTransaction lambda表达式中的“旧学校时尚”中,在它的末尾。

在foreach循环以及LINQ查询中会出现真正的差异。

它与定义变量的闭包(范围)的生命周期有关(在foreach循环或LINQ表达式中)。 在某些版本中,变量在循环的每次迭代中重新定义,而在其他情况下,其生命周期跨越循环的整个执行,在迭代之间保持旧值。 这可能会对结果产生很大影响,具体取决于代码。

我无法解释它比Eric Lippert(在微软工作了16年,开发编译器,包括C#编译器)更好:

http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

我确实看到过以不同方式运行的代码,具体取决于traget框架(因此也取决于C#版本)。 必须考虑到这一点。

大多数时候R#是正确的,就像在这个场合一样。

您可以使用Linq ForEach删除开环。

 db.Table().Where(l => l.PlatypusId == item). Where(l=> l.SentTimeUTC >= EarliestToShow). Where(l=> l.SentTimeUTC <= LatestToShow). OrderBy(l => l.SentTimeUTC).ToList(). ForEach(q => listLocs.Add(q));