我注意到阅读时有一些好奇的事情IDataReader
在我无法理解的 using 语句中。虽然我确信答案很简单。
为什么在里面时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
}
Summary:该方法的两个版本defer, 但是因为ReadSomeProcExt
不推迟执行,在执行传递回调用者之前(即之前Enumerate<T>
能跑)。ReadSomeProc
另一方面,在将读取器传递回调用者之前不会创建读取器,因此在读取所有值之前不会释放容器。
当你的方法使用yield return
,编译器实际上更改了编译后的代码以返回IEnumerable<>
, and 方法中的代码将不会运行,直到其他代码开始迭代返回的IEnumerable<>
.
这意味着下面的代码甚至不会运行您的第一行Enumerate
方法,然后再处理读取器并返回值。当其他人开始迭代你返回的值时IEnumerable<>
,读者已经处理完毕。
using(SqlDataReader rd = cmd.ExecuteReader()){
return rd.Enumerate<T>();
}
但是这段代码会执行整个Enumerate()
方法以产生List<>
返回前的结果:
using(SqlDataReader rd = cmd.ExecuteReader()){
return rd.Enumerate<T>().ToList();
}
另一方面,无论是谁calling具有此代码的方法在计算结果之前实际上并不执行该方法:
using(SqlDataReader rd = cmd.ExecuteReader()){
while(rd.Read())
yield return rd.ConvertTo<T>(); //extension method wrapping FastMember
}
但是当他们执行返回的那一刻IEnumerable<>
, the using
块打开了,但没有打开Dispose()
直到IEnumerable<>
完成迭代,此时您已经从数据读取器读取了所需的所有内容。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)