「利回り」を伴うこの関数は、具体的にどのように機能するのでしょうか?

StackOverflow https://stackoverflow.com/questions/3438670

質問

このメソッド (Unity C# スクリプト内) を取得しましたが、「yield」部分が実際にどのように機能するのか理解できません。

MSDN から、関数が IEnumerator を返し、反復処理できることはわかっていますが、このコードは 1.5 秒待機し、反復されません。これは、内部で作成されたオブジェクトが複数回作成されたことを意味するためです。このコードがどのように機能するかを説明できる人はいますか?

IEnumerator DestroyShip()
{
    // create new gameobject
    Instantiate(ExplosionPrefab, transform.position, transform.rotation);
    // make current gameobject invisible
    gameObject.renderer.enabled = false;
    // set new position for the current gameobject
    transform.position = new Vector3(0f, transform.position.y, transform.position.z);
    // wait for 1,5 seconds 
    yield return new WaitForSeconds(1.5f);
    // make the current gameobject visible again
    gameObject.renderer.enabled = true;
}
役に立ちましたか?

解決

コンパイラが生成する列挙子は反復されます。一度。

コンパイラは、MoveNext() 関数と Current プロパティを持つ IEnumerator を実装するクラスを生成します。このクラスには、呼び出し間の関数の状態を保存するために必要なすべてのメンバーが含まれます。正確な詳細は「コンパイラの魔法」と考えることができます。

この生成されたクラスのオブジェクトは、Unity3d エンジンによって処理および管理されます。Unity3d エンジンは、(別段の指示がない限り) フレームごとに各アクティブなコルーチンで MoveNext() を呼び出します。

これにより、Unity3d プログラマは一度に 1 フレームずつ再生されるスクリプトを作成できるようになりました。C# コンパイラの魔法と Unity3d エンジンの魔法を組み合わせることで、非常に強力でありながら使いやすいスクリプトが作成されます。

あなたの質問に答えるには:関数内のコードは 1 回実行されますが、「yield return」ステートメントで一時停止します。

上で述べたように、IEnumerator を実装する特殊なオブジェクトは C# コンパイラによって作成されます。

MoveNext() への最初の呼び出しで、関数は爆発を作成し、現在のオブジェクトを "new WaitForSeconds(1.5f)" に設定します。

Unity3d エンジンはこのオブジェクトを検査し、それが特別なクラス「WaitForSeconds」のインスタンスであることを確認し、列挙子を待機キューに置き、1.5 秒が経過するまで 2 番目の要素を要求しません。その間、多くのフレームがレンダリングされ、爆発が再生されます。

1.5 秒後、Unity はキューから列挙子を取得し、MoveNext() を再度呼び出します。関数の 2 番目の部分が実行されますが、2 番目のオブジェクトの生成は失敗します。MoveNext() は、新しい要素の取得に失敗したことを示す false を返します。これは、この列挙子を破棄するように Unity3d に通知します。ガベージ コレクターは、ある時点でメモリを再利用します。

言われるように:多くのコンパイラと Unity3d の魔法が進行中です。各 yield return ステートメントで関数が次のフレームまで保留されることを覚えていれば、これらの特別な関数のメリットを十分に理解できるでしょう。

他のヒント

yieldが一度使用された場合は、一つの要素とのIEnumeratorを返したかのように

は、それはあなたがそれを反復しないという印象を得る理由です、です。

それはyieldキーワードのかなり奇妙な使用ですが、それは全体の文脈を見ることなく、それがそのように実装された理由を理解することは困難です。

それは使いやすく、よりflaxibleであり、以下のように IEnumerableではなくIEnumeratorを返すことをお勧めします。それも、より良い使用IEnumerable<T>にあります。収量リターンイテレータブロックを実現するためだけ糖衣構文であり、それは本質的に容易にプログラム的に生成することができる標準のボイラープレートであるように、コンパイラはreleventコードを生成します。あなたは、単一の一連の動作は、コレクションであることをつくれようにしたいときは、一般的に例えば、歩留まりのリターンを使用します。

public IEnumerable<Thing> GetThings()
{
    yield return GetNextThing();
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top