ReSharper が「暗黙的にキャプチャされたクロージャ」と表示するのはなぜですか? 質問する

ReSharper が「暗黙的にキャプチャされたクロージャ」と表示するのはなぜですか? 質問する

次のコードがあります:

public double CalculateDailyProjectPullForceMax(DateTime date, string start = null, string end = null)
{
    Log("Calculating Daily Pull Force Max...");

    var pullForceList = start == null
                             ? _pullForce.Where((t, i) => _date[i] == date).ToList() // implicitly captured closure: end, start
                             : _pullForce.Where(
                                 (t, i) => _date[i] == date && DateTime.Compare(_time[i], DateTime.Parse(start)) > 0 && 
                                           DateTime.Compare(_time[i], DateTime.Parse(end)) < 0).ToList();

    _pullForceDailyMax = Math.Round(pullForceList.Max(), 2, MidpointRounding.AwayFromZero);

    return _pullForceDailyMax;
}

さて、私はその行にコメントを追加しましたリシャーパー変更を提案しています。これはどういう意味ですか、またはなぜ変更する必要があるのですか?implicitly captured closure: end, start

ベストアンサー1

警告は、このメソッド内のラムダが存続するため、変数endも存続することを通知します。start

短い例を見てみましょう

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    int i = 0;
    Random g = new Random();
    this.button1.Click += (sender, args) => this.label1.Text = i++.ToString();
    this.button2.Click += (sender, args) => this.label1.Text = (g.Next() + i).ToString();
}

最初のラムダで「暗黙的にキャプチャされたクロージャ:g」という警告が出ますgゴミ収集最初のラムダが使用されている限り。

コンパイラは両方のラムダ式のクラスを生成し、ラムダ式で使用されるすべての変数をそのクラスに配置します。

したがって、私の例ではg、 と はiデリゲートの実行のために同じクラスに保持されます。gが大量のリソースが残っている重いオブジェクトである場合、ラムダ式が使用されている限りこのクラス内の参照がまだ有効なため、ガベージ コレクターはそれを回収できません。したがって、これは潜在的なメモリ リークであり、これが R# 警告の原因です。

@splintor C# と同様に、匿名メソッドは常にメソッドごとに 1 つのクラスに格納されますが、これを回避するには 2 つの方法があります。

  1. 匿名メソッドの代わりにインスタンスメソッドを使用します。

  2. ラムダ式の作成を 2 つの方法に分割します。

おすすめ記事