在for循环中使用匿名方法的闭包

本文关键字:方法 闭包 for 循环 | 更新日期: 2023-09-27 18:14:04

我试图理解闭包,已经阅读了一些材料,但是…然后我尝试了这个。

据我所知,生成的类包含特定的匿名方法(在我的情况下,写入控制台的方法)和int变量j。它如何将所有j值仅存储在一个类中?在后台是否生成了许多这种类的实例?

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

在for循环中使用匿名方法的闭包

这是你的代码反编译成类而不是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);
        }
    }
}

如您所见,例如循环的迭代,您会得到一个新的new Program.'u003C'u003Ec__DisplayClass2_0();实例。

是的,生成了许多实例。

您需要在循环体的作用域中添加一个额外的变量j,因为变量i具有方法体的作用域,并且只会为它生成一个闭包对象。

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>>();
结果

0
() => value(UserQuery+<>c__DisplayClass1_0).j
UserQuery+<>c__DisplayClass1_0
1
() => value(UserQuery+<>c__DisplayClass1_0).j
UserQuery+<>c__DisplayClass1_0
False