Reputation: 2620
I am trying to understand closures, already read some materials but.. then i tried this.
As far as i understand, a class is generated containing the specific anonymous method (in my case, the one writing to the console) and the int variable j. How does it store all the j values in only one class? Are there many instances of this kind of class generated behind the scenes?
class Program
{
public static List<Action> actions = new List<Action>();
static void Main(string[] args)
{
AddActions(10);
actions[0]();
actions[1]();
Console.ReadLine();
}
public static void AddActions(int count)
{
for (int i = 0; i < count; i++)
{
int j = i;
actions.Add(delegate()
{
Console.Write("{0} ", j);
});
}
}
}
with result: 0 1
Upvotes: 2
Views: 156
Reputation: 117064
Here is your code decompiled into classes rather than lambdas.
private class Program
{
public static List<Action> actions;
static Program()
{
Program.actions = new List<Action>();
}
private static void Main(string[] args)
{
Program.AddActions(10);
Program.actions[0]();
Program.actions[1]();
Console.ReadLine();
}
public static void AddActions(int count)
{
for (int index = 0; index < count; ++index)
{
Program.\u003C\u003Ec__DisplayClass2_0 cDisplayClass20 = new Program.\u003C\u003Ec__DisplayClass2_0();
cDisplayClass20.j = index;
Program.actions.Add(new Action((object)cDisplayClass20, __methodptr(\u003CAddActions\u003Eb__0)));
}
}
private sealed class \u003C\u003Ec__DisplayClass2_0
{
public int j;
public \u003C\u003Ec__DisplayClass2_0()
{
base.\u002Ector();
}
internal void \u003CAddActions\u003Eb__0()
{
Console.Write("{0} ", (object)this.j);
}
}
}
As you can see, for example iteration of the loop you get a new instance of new Program.\u003C\u003Ec__DisplayClass2_0();
.
Upvotes: 1
Reputation: 7681
Yes, many instances are generated.
You need an the extra variable j in the scope of the loop body because the variable i has a scope of the method's body, and only a single closure object would be generated for it.
void Main()
{
AddActions(10);
var closure1 = functions[0]();
var closure2 = functions[1]();
Console.WriteLine(object.ReferenceEquals(closure1, closure2));
// False
}
public static void AddActions(int count)
{
for (int i = 0; i < count; i++)
{
int j = i;
functions.Add(delegate()
{
Console.WriteLine(j);
Expression<Func<int>> exp = () => j;
Console.WriteLine(exp.ToString());
var m = (MemberExpression)exp.Body;
var c = (ConstantExpression)m.Expression;
Console.WriteLine(c.Value.ToString());
return c.Value;
});
}
}
public static List<Func<object>> functions = new List<Func<object>>();
Result
0
() => value(UserQuery+<>c__DisplayClass1_0).j
UserQuery+<>c__DisplayClass1_0
1
() => value(UserQuery+<>c__DisplayClass1_0).j
UserQuery+<>c__DisplayClass1_0
False
Upvotes: 0