【问题标题】:AddListener in foreachforeach 中的添加侦听器
【发布时间】:2016-07-15 00:11:13
【问题描述】:

foreach 语句中的 lambda 突然出现问题:

IEnumerator RefreshNextFrame( Part Current )
{
    yield return null;
    if( Current.Nodes == null )
        yield break;
    Current.Nodes.ForEach( n => Debug.Log( n.name ) );//outputs node0, node1
    for( int i = 0; i < Current.Nodes.Count; i++ )
    {
        Node node = Current.Nodes[i];
        Button button = Instantiate( Resources.Load<GameObject>( "Prefabs/Button" ) ).GetComponent<Button>();
        button.transform.SetParent( content );
        button.GetComponentInChildren<Text>().text = node.name;
        button.onClick.AddListener( delegate
        {
            Debug.Log( button.GetComponentInChildren<Text>().text );
        } );
    }
}

点击按钮总是输出node1

【问题讨论】:

  • 尝试将 Current.Nodes.ForEach( n => Debug.Log( n.name ) ); 行放入 lambda 表达式中,看看两个节点是否还有你期望的名字。也许你稍后在代码的其他地方覆盖它们而不知道。
  • 不。我期望的名字。
  • 这段代码在 couroutine 中。这有意义吗?
  • 尝试将 button. 放在 lambda 表达式中的 GetComponentInChildren().text 之前。也许您甚至没有从按钮中获取孩子,而是从该代码所在的对象中获取。所以该行看起来像这样: Debug.Log( button.GetComponentInChildren().text );
  • 是的,这是不对的,但现在它是所有按钮上的 node1 输出。同样的问题。

标签: c# unity3d foreach lambda


【解决方案1】:

只需在每次迭代时分配一个新的局部变量,并将该局部变量用于 AddListener。

编辑 快速示例:

MyFunction 将始终收到 100 作为 i 的值:

for (int i=0; i<100; i++) {
    button.onClick.AddListener(() => MyFunction(i));
}

但如果你这样做,它将正常工作:

for (int i=0; i<100; i++) {
    int iLocal = i;
    button.onClick.AddListener(() => MyFunction(iLocal));
}

【讨论】:

  • 我们已经讨论过了,它不起作用,因为他的代码是在 Unity 协同程序中执行的,它本身已经是某种带有保存上下文的 lambda 表达式。在其中创建 lambda 表达式不会保存上下文,这就是它不起作用的原因。
【解决方案2】:

因为这段代码,一切都在 couroutine 中。这是答案http://answers.unity3d.com/answers/974195/view.html

【讨论】:

  • 有趣,所以 lambda 里面的 lambda 不会复制上下文。 :)
猜你喜欢
  • 2011-08-16
  • 2012-01-07
  • 2013-02-17
  • 2014-01-30
  • 2011-09-28
  • 1970-01-01
  • 2016-12-06
  • 2011-08-21
  • 2015-08-23
相关资源
最近更新 更多