C#lambda调用for循环引用最后一个对象 [英] C# lambda call in for loop references to last object

查看:105
本文介绍了C#lambda调用for循环引用最后一个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经研究了这个问题,并且尝试按照之前几个问题中的说明修复代码(

I've researched this problem and I've tried fixing the code as instructed in a few questions before (such as this one) but it still won't work. Though I must say that all the answers I checked were from 2009-2010 so they might be obsolete.

这是罪魁祸首代码:

            foreach(Entity player in players)
            {
                if(player.actions.Count > 0)
                {
                    Entity temp = player;

                    player.isDoingAction = true;
                    Debug.Log(player.name + " started action");

                    player.actions.Dequeue().Execute(() => { temp.isDoingAction = false; Debug.Log(temp.name + " finished"); });
                }
            }

这将打印以下内容:

Player1 started action
Player2 started action
Player2 finished
Player2 finished

何时打印:

Player1 started action
Player2 started action
Player1 finished
Player2 finished

或类似的东西.

此代码在Unity协程函数中运行.

This code runs in a Unity coroutine function.

代码中的片段较大:

GameManager.cs

private IEnumerator RunTurn()
{
    ...
    ...
    ...

    for(int i = 0; i < phases; i++)
    {
        //Assign action to each player
        foreach(Entity player in players)
        {
            if(player.actions.Count > 0)
            {
                Entity temp = player;

                player.isDoingAction = true;
                Debug.Log(player.name + " started action");
                player.actions.Dequeue().Execute(() => { temp.isDoingAction = false; Debug.Log(temp.name + " finished"); });
            }
        }

        //Wait for each player to finish action
        foreach(Entity player in players)
        {
            while(player.isDoingAction == true)
            {
                Debug.Log("Waiting for " + player.name);
                yield return null;
            }
        }
    }

    ...
    ...
    ...
}

Action.cs

public override void Execute(System.Action callback)
{
    Move(callback);             
}

private void Move(System.Action callback)
{
    ...
    ...
    ...

    //Move target entity
    target.MoveToPosition(newPosition, mSpeed, callback);
    target.location = newLocation;

    ...
    ...
    ...
}

Entity.cs

public void MoveToPosition(Vector3 position, float speed, System.Action callback)
{
    StartCoroutine(CoMoveToPosition(position, speed, callback));
}

//Move to position
private IEnumerator CoMoveToPosition(Vector3 position, float speed, System.Action callback)
{
    while(position != transform.position)
    {
        transform.position = Vector3.MoveTowards(transform.position, position, speed * Time.deltaTime);
        yield return null;
    }

    //Move finished so use callback
    callback();
}

解决方案

事实证明,Unity中存在带有协程和匿名Lambda回调的错误.在链接中进行检查更多.

It turns out there is a bug in Unity with coroutines and anonymous lambda callbacks. Check this link for more.

有效的代码段:

foreach(Entity player in players)
{
    if(player.actions.Count > 0)
    {
        player.isDoingAction = true;
        Debug.Log(player.name + " started action");

        System.Func<Entity, System.Action> action = new System.Func<Entity,System.Action>(p =>
        new System.Action(() => { p.isDoingAction = false; Debug.Log(p.name + " finished"); }));

        player.actions.Dequeue().Execute(action(player));
    }
}

推荐答案

您可以通过以下方式捕获值:

You can capture the value the following way:

var action = new Func<Entity, Action>(p => 
new Action(() => { p.isDoingAction = false; Debug.Log(p.name + " finished")); })(player);
player.actions.Dequeue().Execute(action);

这篇关于C#lambda调用for循环引用最后一个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆