使用yield return将代码拆分为不同的方法

时间:2013-06-03 22:16:24

标签: c# yield-return

我正在实施一个用于运行游戏AI脚本的光纤系统,我遇到了一个小问题。

我使用yield return x来表示脚本中的等待x帧。我想封装计算x帧的逻辑,因为其他事件可以修改要等待的帧数。我理想的解决方案如下:

public Boolean removeScript = false;

public IEnumerable update()
{
    while(true)
    {
        shootAtPlayer()
        wait(30)
    }
}

private IEnumerable wait(int x)
{
    yield return removeScript ? -1 : x;
}

wait()指示返回30或者如果不再需要脚本则返回-1。迭代器将通过删除脚本来处理-1返回。如果x> 0迭代器会每帧递减一次返回0,然后再次调用update()。

但是这不起作用,因为wait()的yield return不会传播到update方法。这会导致代码重复,模块化程度降低,代码可读性降低:

public IEnumerable update()
{
    while(true)
    {
        shootAtPlayer()
        yield return removeScript ? -1 : x;
    }
}

我想知道是否有更好的方法来构建它?或者是否有我遗漏的语言功能在这种情况下会有用?

1 个答案:

答案 0 :(得分:1)

在这种特定情况下,解决方案相对简单:make Wait()只返回整数:

public IEnumerable Update()
{
    while (true)
    {
        ShootAtPlayer();
        yield return Wait(30);
    }
}

private int Wait(int x)
{
    return removeScript ? -1 : x;
}

在更复杂的情况下,您可以使用foreach,但这会使语法更加冗长:

public IEnumerable Update()
{
    while (true)
    {
        ShootAtPlayer();

        foreach (var x in Wait(30))
            yield return x;
    }
}

private IEnumerable Wait(int x)
{
    yield return removeScript ? -1 : x;
}

正如您所看到的,您可以(ab)使用yield return来实现光纤,但yield return从未意味着这一点,因此效果不佳。

为此类异步延续所做的是新async - await。有了这个,你的代码可以找到这样的例子:

public async Task Update()
{
    while (true)
    {
        ShootAtPlayer();
        await Wait(30);
    }
}

private async Task Wait(int x)
{
    await fiber.Wait(removeScript ? -1 : x);
}

作为最后一点,我认为你使用removeScript的方式并不是一个好主意。脚本的结尾应该由实际完成的Update()方法表示(可枚举的项目没有,或者Task完成),而不是通过返回魔术值。