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 回答