LINQifying我的代码值得在闭包中访问一个foreach变量吗?

让人想起滚滚乐队滚石乐队昔日唱片的头衔,Resharper比我永远都要犀利; 因为我检查了我的代码,它告诉了我关于闭包的事情:

1)“循环:

        foreach (var item in PlatypiIds)
        {
            var query = db.Table<Locations>().Where(l => l.PlatypusId == item).
                Where(l=> l.SentTimeUTC >= EarliestToShow).
                Where(l=> l.SentTimeUTC <= LatestToShow).
                OrderBy(l => l.SentTimeUTC);

            if (query != null)
            {
                foreach (var q in query)
                {
                    listLocs.Add(q);
                }
            }
        }

...可以转换成LINQ表达式:

listLocs.AddRange(from item in PlatypiIds select db.Table<Locations>().Where(l => l.PlatypusId == item).Where(l => l.SentTimeUTC >= EarliestToShow).Where(l => l.SentTimeUTC <= LatestToShow).OrderBy(l => 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<PlatypiRequested>();

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

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

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


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

关于ReSharper,告诉你“在关闭时访问foreach变量...”,当代码被LINQ化时 - 我只是从未抓住机会,把它作为一个foreach循环。 在大多数情况下,它的可读性和可维护性也更高,而且缩短代码并不是什么大不了的事情。

关于第二种情况 - 您将需要丢失using语句,因为db对象将尽快处理。 您应该关闭它,并将其RunInTransactionRunInTransaction 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<Locations>().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));
链接地址: http://www.djcxy.com/p/52817.html

上一篇: Is LINQifying my code worth accessing a foreach variable in a closure?

下一篇: How do I fix: Access to foreach variable in closure resharper warning?