1. ホーム
  2. c#

[解決済み】C#のyieldキーワードは何に使われるのか?

2022-03-23 14:09:07

質問

IListの一部分のみを公開するにはどうしたらいいですか? の質問で、回答の1つに以下のコードスニペットがありました。

IEnumerable<object> FilteredList()
{
    foreach(object item in FullList)
    {
        if(IsItemInPartialList(item))
            yield return item;
    }
}

yieldキーワードはそこで何をするのでしょうか? いくつかの場所で言及されているのを見たし、他の質問でも見たのですが、実際に何をするのかがよくわかりません。 私は、あるスレッドが別のスレッドに降伏するという意味でyieldを考えるのに慣れていますが、ここではそれは関係ないように思えます。

どのように解決するのですか?

その yield というキーワードは、実はここで非常に大きな役割を果たします。

を実装したオブジェクトを返します。 IEnumerable<object> インターフェイスを使用します。呼び出し側の関数が foreach このオブジェクトの上に乗っている関数は、それが "yields"するまで再度呼び出されます。これは C# 2.0 . それ以前のバージョンでは IEnumerableIEnumerator オブジェクトを使用して、このようなことを行います。

このようなコードを理解する最も簡単な方法は、例をタイプインして、いくつかのブレークポイントを設定し、何が起こるか見ることです。この例でステップを踏んでみてください。

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}

この例をステップ実行すると、最初の呼び出しが Integers() は以下を返します。 1 . 2回目の呼び出しでは 2 という行と yield return 1 が再び実行されることはありません。

以下は実際の例です。

public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)
{
    using (var connection = CreateConnection())
    {
        using (var command = CreateCommand(CommandType.Text, sql, connection, parms))
        {
            command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return make(reader);
                }
            }
        }
    }
}