【问题标题】:C# Anonymous method variable scope problem with IEnumerable<T>IEnumerable<T> 的 C# 匿名方法变量范围问题
【发布时间】:2010-04-13 09:26:07
【问题描述】:

我正在尝试遍历所有组件,并且对于那些实现 ISupportsOpen 的人允许打开一个项目。 问题是当调用匿名方法时,组件变量总是相同的元素(来自 IEnumerable 的外部作用域)

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

请问应该怎么解决?

【问题讨论】:

    标签: c# generics scope anonymous-methods


    【解决方案1】:

    只是不要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 变量的新“实例”——因此每个委托都会捕获该不同的实例。以前,每个委托都在捕获相同的变量。

    (这在某些方面是一个重复的问题,但它是一种相对难以搜索的问题,所以我很乐意回答它很多次。)

    【讨论】:

    • 我只是好奇,当他知道正在使用该实例时,为什么运行时不将该实例保存在内存中?为什么在捕获相同变量之前委托?
    • @PaN1C_Showt1Me:语言规范以单个变量的形式定义foreach;该变量已被捕获,因此一切都按照规范工作。 (这是一个语言问题,而不是运行时问题。)有关更多详细信息,请参阅 Eric 的博客文章(链接)。我敢肯定,如果语言设计者有一台时间机器,他们会改变 foreach 的行为——但现在为时已晚。
    猜你喜欢
    • 2013-12-29
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 2016-06-21
    • 1970-01-01
    • 2012-05-18
    • 1970-01-01
    • 2013-01-11
    相关资源
    最近更新 更多