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 は後で「新しく改善された」コードについて次のように語っています。

では、異なるバージョンのコンパイラでコンパイルする可能性は何ですか? つまり、たとえば、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 ループにも実際の違いがあります。

これは、変数が (foreach ループまたは LINQ 式で) 定義されているクロージャー (スコープ) の有効期間に関係しています。一部のバージョンでは、変数はループの反復ごとに再定義されます。また、別の場合では、変数の有効期間はループの実行全体にまたがり、反復間で古い値が保持されます。コードによっては、結果に大きな違いが生じる可能性があります。

Eric Lippert (Microsoft に 16 年間勤務し、C# コンパイラを含むコンパイラの開発者) ほどうまく説明することはできません。

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

ターゲット フレームワーク (したがって C# のバージョン) に応じて、異なる方法で動作するコードを実際に見てきました。これを考慮する必要があります。

この場合のように、ほとんどの場合、R# は正しいです。

于 2013-04-24T09:00:58.523 に答える
2

ここには 2 つの異なる問題があります。1 つは LINQ と foreach、もう 1 つは別のケースです。

コードがLINQ化されているときに「クロージャーでforeach変数にアクセス...」と通知するReSharperについて-私はチャンスを逃さず、foreachループのままにします。ほとんどの場合、読みやすく保守しやすく、実際には、コードを短くすることはそれほど大したことではありません。

2 番目のケースについては、オブジェクトがすぐに破棄されるusingため、ステートメントを失う必要があります。最後に、ラムダ式dbの内側で「古い学校のやり方」で閉じて処分する必要があります。RunInTransaction

于 2012-12-04T23:30:18.377 に答える
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 に答える