2013-02-18 58 views
0

我知道很多问题已经在C#关闭中提出并回答或讨论过。但是,请饶了我一点点时间对我的小实验......关于C#关闭的另一个问题

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Timers; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     using (var timer = new Timer(500)) 
     { 
     timer.AutoReset = false; 

     GetFunc2(timer, 0); 
     // GetFunc3(timer, 0); 

     timer.Start(); 

     Console.ReadLine(); 
     } 
    } 

    static void GetFunc2(Timer timer, int i) 
    { 
     for (; i < 5; ++i) 
     { 
     timer.Elapsed += (obj, e) => 
      { 
      Console.WriteLine(i); 
      }; 
     } 
    } 

    static void GetFunc3(Timer timer, int i) 
    { 
     timer.Elapsed += (obj, e) => 
     { 
     Console.WriteLine(i++); 
     }; 

     timer.Elapsed += (obj, e) => 
     { 
     Console.WriteLine(i++); 
     }; 

     timer.Elapsed += (obj, e) => 
     { 
     Console.WriteLine(i++); 
     }; 

     timer.Elapsed += (obj, e) => 
     { 
     Console.WriteLine(i++); 
     }; 

     timer.Elapsed += (obj, e) => 
     { 
     Console.WriteLine(i++); 
     }; 
    } 
    } 
} 

通过调用MainGetFunc2GetFunc3独立,我们可以看到输出是不同的,虽然看起来GetFun3仅仅像GetFunc2简单地扩大。任何人都知道为什么?我认为ildasm可以揭示不同的生成代码,但我确实想知道为什么。测试VS2012 Pro,.net 4.5。

+0

您可能希望为我们提供您看到的不同输出,并非每个人都可以访问C#编译器 – Lukazoid 2013-02-18 00:13:31

+0

请给这个更精确的标题。按照它的规定,这个问题是关于一段代码的,你需要更一般地阐述它,所以我投票结果太过本地化。 – djechlin 2013-02-18 00:28:48

+0

@djechlin被问到的问题非常明确,这是一个普遍的原则。如果你能想出更好的标题,请随时编辑问题。 – 2013-02-18 00:31:32

回答

3

这已经覆盖倍量是巨大的..

我不会在讨论了,但看埃里克利珀的答案,这里的人:

https://stackoverflow.com/a/8899347/1517578

的对这些答案的评论也是有趣的阅读。

此外,链接Eric的博客文章正是在这里:http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

基本上,你需要复制被关闭了到一个局部变量的变量:

static void GetFunc2(Timer timer, int i) 
{ 
    for (; i < 5; ++i) 
    { 
    int i2 = i; // STORE IT 
    timer.Elapsed += (obj, e) => 
     { 
     Console.WriteLine(i2); // USE THE NEWLY STORED VERSION 
     }; 
    } 
} 

这导致:

0 
1 
2 
3 
4 

如预期的那样。

0

AFAIK封闭始终包含引用局部变量的“父”方法。所以不同之处在于,在实际调用GetFunc2中的这些函数之前,您正在增加该值。所以在调用的时候,已经有5个值了。在GetFunc3中,您在提高事件时递增该值,因此它会计数。

0

如果是GetFunc2,您在调用(执行)匿名方法之前增加i,因此当您调用所看到的方法时,i已经增加。

GetFunc3的情况下,您不会增加i,直到每个匿名方法被调用,因此它从零开始并随着每次调用而增加。