使用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()指示yield返回30,如果不再需要脚本则返回-1。迭代器将通过删除脚本来处理-1返回值。如果x> 0,迭代器将每一帧递减返回值,直到0,然后再次调用update()。

然而,这不起作用,因为wait()的yield返回当然不会传播到更新方法。这会导致代码重复,更差的模块化和可读性更差的代码:

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

我想知道是否有更好的方法来构建这个?或者在这种情况下,我缺少了一个有用的语言功能?

在这种特殊情况下,解决方案相对简单:使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完成),而不是通过返回一个魔术值来表示。

最新更新