I have the following code:
public double CalculateDailyProjectPullForceMax(DateTime date, string start = null, string end = null)
{
Log(\"Calculating Dai
The warning is valid and displayed in methods that have more than one lambda, and they capture different values.
When a method that contains lambdas is invoked, a compiler-generated object is instantiated with:
As an example:
class DecompileMe
{
DecompileMe(Action callable1, Action callable2)
{
var p1 = 1;
var p2 = "hello";
callable1(() => p1++); // WARNING: Implicitly captured closure: p2
callable2(() => { p2.ToString(); p1++; });
}
}
Examine the generated code for this class (tidied up a little):
class DecompileMe
{
DecompileMe(Action callable1, Action callable2)
{
var helper = new LambdaHelper();
helper.p1 = 1;
helper.p2 = "hello";
callable1(helper.Lambda1);
callable2(helper.Lambda2);
}
[CompilerGenerated]
private sealed class LambdaHelper
{
public int p1;
public string p2;
public void Lambda1() { ++p1; }
public void Lambda2() { p2.ToString(); ++p1; }
}
}
Note the instance of LambdaHelper
created stores both p1
and p2
.
Imagine that:
callable1
keeps a long-lived reference to its argument, helper.Lambda1
callable2
does not keep a reference to its argument, helper.Lambda2
In this situation, the reference to helper.Lambda1
also indirectly references the string in p2
, and this means that the garbage collector will not be able to deallocate it. At worst it is a memory/resource leak. Alternatively it may keep object(s) alive longer than otherwise needed, which can have an impact on GC if they get promoted from gen0 to gen1.