简体   繁体   中英

Closures with anonymous methods in a for loop

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

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.\<\>c__DisplayClass2_0(); .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM