3

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 告诉我,“访问已处置的关闭”

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

4

3 回答 3

2

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

关于 ReSharper 在代码是 LINQified 时通知您“访问闭包中的 foreach 变量...” - 我只是从不冒险,并将其保留为 foreach 循环。在大多数情况下,它也更具可读性和可维护性,实际上,缩短代码并不是什么大不了的事。

关于第二种情况 - 您需要丢失该using语句,因为该db对象将被处理得太早。RunInTransaction您应该在lambda 表达式的末尾以“老式方式”关闭并处理它。

于 2012-12-04T23:30:18.377 回答
2

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

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

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

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

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

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

于 2013-04-24T09:00:58.523 回答
0

您可以使用 LinqForEach删除开环。

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));
于 2012-12-04T23:35:12.183 回答