web-dev-qa-db-ja.com

暗黙的にキャプチャされたクロージャ、ReSharper警告

私は通常、「暗黙的にキャプチャされた閉鎖」の意味を知っていますが、今日は次のような状況に遭遇しました。

public static void Foo (Bar bar, Action<int> a, Action<int> b, int c)
{
    bar.RegisterHandler(x => a(c)); // Implicitly captured closure: b
    bar.RegisterHandler(x => b(c)); // Implicitly captured closure: a
}

他のアクションも暗黙的にキャプチャするのはなぜですか?両方の行のいずれかをコメントにすると、もう一方は警告を表示しません。誰かがReSharperが私に警告しているどんな危険を知っていますか?

編集:ReSharper 8.0.1

32
D.R.

ここでの問題は、バックグラウンドで発生する変数を閉じると、コンパイラが名前のない新しい型を作成し、その型にインスタンスフィールドを与えることですそのブロックで閉じられるすべての変数、そのコードブロック内のすべての匿名メソッドのメソッドを提供し、そのオブジェクトの単一インスタンスを渡します。

これは、最初のデリゲートの存続期間がそのクロージャオブジェクトを存続させることであり、内部にはbに加えてオブジェクトaへの参照があり、その逆も同様であることを意味します。

Actionは特にメモリを集中的に使用するものではないため、問題はありません。少し長く存続させることは、実際には問題になりません。

理論的には、C#チームは、この特定のケースでは、同じブロック内のクロージャーごとに新しい名前なしタイプを作成できることを確認できましたが、一般的なケースを悪化させるため、そうしないことを選択しました。

35
Servy

そして警告、私はこれに怒っていました:

List<List<string>> allowed = AllowedSCACSwaps;
foreach (List<string> c in allowed.Where(c => c.Contains(scac)))
{
    csc = openCycles.FirstOrDefault(icsc => (icsc.CustomerCode == customerCode) && c.Contains(icsc.SCAC));
    if (null != csc)
    {
        return csc;
    }
}

「customerCodeの暗黙の閉鎖」と言う

string cc = customerCode.ToUpperInvariant();
string sc = scac.ToUpperInvariant();    List<List<string>> allowed = AllowedSCACSwaps;
    foreach (List<string> c in allowed.Where(c => c.Contains(sc)))
    {
        csc = openCycles.FirstOrDefault(icsc => (icsc.CustomerCode == cc) && c.Contains(icsc.SCAC));
        if (null != csc)
        {
            return csc;
        }
    }

結構です。

私が狂っていた理由は?

scacとcustomerCodeはどちらもメソッドに渡される文字列です。しかし、customerCodeをccに置き換えても、同じ警告が表示され続けました。

閉鎖は実際にはscacを超えていましたが、Resharperはそれを誤って報告していました。

0
Roger Willcocks

私はこれを以前に見たことがあります。ラムダの存続期間中に保持される変数と関係があるため、変数が大きい場合、メモリにプレッシャーがかかる可能性があります。

0
Allan Elder