任何收益类型的通用类型

Universal type for any yield type

尝试让系统能够存储任何类型的收益指令

YieldInstruction m_yield;

void SetInstruction()
{
    switch(condition)
    {
        case UseWait:
            m_yield = new WaitForSeconds(1f);
            break;
        case UseWaitUntil:
            m_yield = new WaitUntil(() => flag == true); // Cannot cast here
    }
}

将类型更改为 IEnumerator 将问题放在第一个上。 CustomeYieldInstruction 也没有做。

我不清楚 YieldInstruction 和 CustomYieldInstruction 之间的关系。尽管名称不同,但一个是它自己的基类型,后者是 IEnumerator。

我也很困惑,因为这两种方法可以在 IEnumerator 方法中产生,但如果按照我正在尝试的方式完成,则不会转换为它。

public sealed class WaitForSeconds : YieldInstruction{ /* ** */ }
public class YieldInstruction { }

public sealed class WaitUntil : CustomYieldInstruction { /* ** */}
public abstract class CustomYieldInstruction : IEnumerator { /* ** */ }

我能做到:

public IEnumerator Sequence()
{
     yield return new WaitForSeconds(1f),
     yield return new WaitUntil(()=> condition == true);
}

YieldInstruction 从 Unity 的内部系统中获得特殊待遇。如果您只查看 WaitUntil,它不需要内部引擎 (C/C++) 的特殊处理,因为它只需要一个 C# 谓词。另一方面,WaitForSecondsWaitForEndOfFrame ofc 需要一些特殊处理。在前者中,它需要内部计时器,在后者中,协程调度程序必须在帧末尾进行特殊中断,这对于托管脚本端来说是不可能的。

另外别忘了你什么都可以出! null 也没有实现 IEnumeratorstring 等..

当您调用 StartCoroutine(MyCoroutine); 时,您基本上是将该方法注册到 Unity 的协程调度程序中,它是在 C/C++ 中实现的。

回到你原来的问题。幸运的是,在 C# 中,每个 class 都继承自 System.Object,因此它们可以有一个基础 class.

除了

我会说使用 object 对我来说有点太脏了。

但是您可以简单地为那些自己不实现它的类型构建一个包装器 IEnumerator(就像基于内部时间的任何东西):

private IEnumerator WaitForYieldInstruction(YieldInstruction instruction)
{
    yield return instruction;
}

然后使用

IEnumerator m_yield;

void SetInstruction()
{
    switch(condition)
    {
        case UseWait:
            m_yield = WaitForYieldInstruction(new WaitForSeconds(1f));
            break;
        case UseWaitUntil:
            m_yield = new WaitUntil(() => flag); 
            break;
    }
}