2010-04-13 67 views
3

我想遍历所有组件,并为那些谁实现ISupportsOpen允许打开一个项目。 问题是,当匿名方法被调用,则组件变量始终是相同的元素(从外部范围来自IEnumerable)C#匿名方法变量范围问题与IEnumerable <T>

foreach (ISupportsOpen component in something.Site.Container.Components.OfType<ISupportsOpen>()) 
{ 
    MyClass m = new MyClass(); 
    m.Called += new EventHandler(delegate(object sender, EventArgs e) 
    {       
     if (component.CanOpenProject(..)) component.OpenProject(..); 
    }); 

    itemsList.Add(m); 
} 

究竟应该如何解决,好吗?

回答

5

只是不要close over the loop variable - 复制:

foreach (ISupportsOpen component in 
     something.Site.Container.Components.OfType<ISupportsOpen>()) 
{ 
    ISupportsOpen copy = component; 
    MyClass m = new MyClass(); 
    m.Called += new EventHandler(delegate(object sender, EventArgs e) 
    {       
     if (copy.CanOpenProject(..)) copy.OpenProject(..); 
    }); 

    itemsList.Add(m); 
} 

你得到copy变量的新“实例”为每个循环迭代这样 - 所以每个代表能捕捉到不同的实例。之前,每个代表都在捕获同一个变量。

(这在某种程度上是一个重复的问题,但它是一种问题,就是比较难以寻找的,所以我很高兴回答了很多次。)

+0

我只是好奇,为什么当知道实例正在被使用时,运行时不会将该实例保存在内存中?为什么代表在捕获相同的变量之前? – 2010-04-13 09:52:12

+0

@ PaN1C_Showt1Me:语言规范根据单个变量定义'foreach';该变量被捕获,所以它都按照规范工作。 (这是一种语言,而不是运行时间的事情。)有关更多详细信息,请参阅Eric的博客文章(链接)。我敢肯定,如果语言设计师有时间机器,他们会改变foreach的行为 - 但现在已经太晚了。 – 2010-04-13 09:59:14