C#警惕匿名方法造成的变量共享实例分析

2019-12-26 14:11:13于丽

.NET中本没有什么“匿名方法”,也没有类似的新特性。“匿名方法”完全是由编译器施展的魔法,它会将匿名方法中需要访问的所有成员一起包含在闭包中,确保所有的成员调用都符合.NET标准。例如在文章第一节中的第2个示例,实际上由编译器处理之后就变成了如下的样子(自然字段名经过“友好化”处理):

 

 
  1. class TestClass  { 
  2. ...  private sealed class AutoGeneratedHelperClass 
  3. {  public TestClass m_testClassInstance; 
  4. public int m_index;  public void Action(string m) 
  5. {  this.m_index++; 
  6. this.m_testClassInstance.Print(m);  } 
  7. }  public void TestAfterCompiled() 
  8. {  AutoGeneratedHelperClass helper = new AutoGeneratedHelperClass(); 
  9. helper.m_testClassInstance = this;  helper.m_index = 0; 
  10. string[] messages = new string[] { "Hello", "World" };  Action<string> action = new Action<string>(helper.Action); 
  11. Array.ForEach(messages, action);  Console.WriteLine(helper.m_index); 
  12. }  } 

由此就可以看出编译器是如何实现一个闭包的:

编译器自动生成一个私有的内部辅助类,并将其设为sealed,这个类的实例将成为一个闭包对象。

如果匿名方法需要访问方法的参数或局部变量,那么该参数或局部变量将“升级”成为辅助类中的公有Field字段。

如果匿名方法需要访问类中的其它方法,那么辅助类中将保存类的当前实例。