2015-09-23 42 views
2

我想了解闭包,已经阅读了一些材料,但..然后我试了这个。在for循环中使用匿名方法的闭包

据我所知,一个类生成包含特定的匿名方法(在我的情况下,写入控制台)和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); 
      }); 
     } 
    } 
} 

与结果:0 1

+0

http://blogs.msdn.com/b/oldnewthing/archive/2006/08/02/686456.aspx – Igor

回答

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 
1

这里是你的代码反编译成类,而不是lambda表达式。

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();一个新的实例。

+0

非常感谢,我越来越意识到这些事情。 –