【发布时间】:2018-01-23 13:15:55
【问题描述】:
我注意到在我无法理解的 using 语句中读取 IDataReader 时有些奇怪。虽然我确信答案很简单。
为什么在using (SqlDataReader rd) { ... } 内,如果我直接执行yield return,阅读器在阅读期间保持打开状态。但是,如果我执行直接return 调用 SqlDataReader 扩展方法(如下所述),读者在实现可枚举之前关闭?
public static IEnumerable<T> Enumerate<T>(this SqlDataReader rd)
{
while (rd.Read())
yield return rd.ConvertTo<T>(); //extension method wrapping FastMember
rd.NextResult();
}
为了完全清楚我的要求,我不确定为什么以下内容存在根本不同:
根据@TimSchmelter 的要求,一个充实的例子:
/*
* contrived methods
*/
public IEnumerable<T> ReadSomeProc<T>() {
using (var db = new SqlConnection("connection string"))
{
var cmd = new SqlCommand("dbo.someProc", db);
using(var rd = cmd.ExecuteReader())
{
while(rd.Read())
yield return rd.ConvertTo<T>(); //extension method wrapping FastMember
}
}
}
//vs
public IEnumerable<T> ReadSomeProcExt<T>() {
using (var db = new SqlConnection("connection string"))
{
var cmd = new SqlCommand("dbo.someProc", db);
using(var rd = cmd.ExecuteReader())
{
return rd.Enumerate<T>(); //outlined above
}
}
}
/*
* usage
*/
var lst = ReadSomeProc<SomeObect>();
foreach(var l in lst){
//this works
}
//vs
var lst2 = ReadSomeProcExt<SomeObect>();
foreach(var l in list){
//throws exception, invalid attempt to read when reader is closed
}
【问题讨论】:
-
我认为您的问题已在MSDN 关于“产量”作用的文章中得到解答。
-
那是因为带有
yield return的方法变成了状态机。出于这个原因,最好不要在using语句中混合惰性初始化。 -
您应该在读取数据的地方显示部分代码。明确一点,第一个版本允许读取,而第二个版本抛出一个异常,即阅读器已关闭?
-
@vipersassassin:嗯,两者都使用
yield return,这就是为什么 OP 想知道为什么他会得到不同的结果。 -
@johnny5 两种解决方案都将读取结果的时间相同。两种解决方案都调用
ConvertTo,而不仅仅是一个,而且它们都是同时调用的。
标签: c# ado.net ienumerable sqldatareader yield-return