0

これは、列挙子プロパティを持つ var 型の非常に単純な (そして無意味な) 例です。IEnumeratorこのスニペットのポイントは、インターフェイスを実装する厳密に型指定されたクラスを使用してコレクションを試すことです。

public class num { public int value { get; set; } }

class Program {

    private int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    static void Main(string[] args) {

        Program p = new Program();
        var numbers = selectNumbers(p.data);


        foreach(num x in numbers) {
            Console.WriteLine("Found {0}", x.value.ToString());
        }

        Console.WriteLine("press [enter] to exit");
        Console.Read();
    }

    static IEnumerable<num> selectNumbers(int[] x) {
        //in production app the following would use a reader to get data from database
        for(int i = 0; i < x.Length; i++) {
            yield return new num { value = x[i] };
            Console.WriteLine("Found {0}", x[i].ToString()); // <<<(1)
        }
    }
}

コンソールに返される結果は少し奇妙です。結果は、ループの繰り返しが実行されるたびに、foreach行 (1) も実行されることを示唆しているようです。

これは、この構造をデータベース設定アプリケーションに実装した場合、selectNumbersデータベースとの接続に関係する場合、IEnumerator が使用されるたびに接続が確立されるということですか? foreachたとえば、厳密に型指定されたものに対してループを使用するたびにnum、データベースにアクセスすることになりますか? この例の結果は、そうであることを示唆しているようです。

4

1 に答える 1

0

それがどのように機能するかyield returnです。コンパイラは、ステート マシンを構築してIEnumerable<T>インターフェイスを実装します。データベース アクセスで示した例はthis post. whileこの例では、ステート マシンは、メソッドの先頭ではなく、ループ内にある前の反復で以前に終了した場所から続行します。

static IEnumerable<MyModel> SelectTop100Models() 
{
    var connectionString = ConfigurationManager.ConnectionStrings["XXX"].ConnectionString;
    using (var conn = new SqlConnection(connectionString))
    using (var cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = "SELECT top 100 * FROM x";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // EXECUTION WILL CONTINUE FROM HERE AND NOT AT THE BEGINNING
                // OF THE METHOD
                yield return new MyModel
                {
                    Id = reader.GetInt32(reader.GetOrdinal("ID")),
                    Name = reader.GetString(reader.GetOrdinal("Name")),
                };
            }
        }
    }
}

したがって、データベースへの複数の接続を作成することについてまったく心配する必要はありません。このコードは非常に最適化されています。

于 2013-03-15T16:43:28.337 に答える