Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
303 views
in Technique[技术] by (71.8m points)

c# - Why does ReSharper tell me "implicitly captured closure"?

I have the following code:

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;
}

Now, I've added a comment on the line that ReSharper is suggesting a change. What does it mean, or why would it need to be changed? implicitly captured closure: end, start

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The warning tells you that the variables end and start stay alive as any of the lambdas inside this method stay alive.

Take a look at the short example

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();
}

I get an "Implicitly captured closure: g" warning at the first lambda. It is telling me that g cannot be garbage collected as long as the first lambda is in use.

The compiler generates a class for both lambda expressions and puts all variables in that class which are used in the lambda expressions.

So in my example g and i are held in the same class for execution of my delegates. If g is a heavy object with a lot of resources left behind, the garbage collector couldn't reclaim it, because the reference in this class is still alive as long as any of the lambda expressions is in use. So this is a potential memory leak, and that is the reason for the R# warning.

@splintor As in C# the anonymous methods are always stored in one class per method there are two ways to avoid this:

  1. Use an instance method instead of an anonymous one.

  2. Split the creation of the lambda expressions into two methods.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...