收益率回报与回报 IE无数<T>



我注意到在 using 语句中读取我无法理解的IDataReader有些奇怪。虽然我确信答案很简单。

为什么在using (SqlDataReader rd) { ... }内,如果我直接执行yield return,阅读器在阅读期间保持打开状态。但是,如果我在调用读取器在实现枚举之前关闭的 SqlDataReader 扩展方法(如下所述(来执行直接return

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
}

摘要:该方法的两个版本都延迟,但由于ReadSomeProcExt不会延迟执行,因此读取器在执行传递回调用方之前(即在Enumerate<T>可以运行之前(被释放。 另一方面,ReadSomeProc在将读取器传递回调用方之前不会创建读取器,因此在读取其所有值之前,它不会释放容器。

当你的方法使用yield return时,编译器实际上会更改编译后的代码以返回一个IEnumerable<>,并且你的方法中的代码不会运行,直到其他代码开始迭代返回的IEnumerable<>

这意味着下面的代码在释放读取器并返回值之前甚至不会运行Enumerate方法的第一行。当其他人开始迭代您返回的IEnumerable<>时,读取器已经被处置了。

using(SqlDataReader rd = cmd.ExecuteReader()){
return rd.Enumerate<T>();
}

但是此代码将执行整个Enumerate()方法,以便在返回之前生成List<>结果:

using(SqlDataReader rd = cmd.ExecuteReader()){
return rd.Enumerate<T>().ToList();
}

另一方面,在评估结果之前,使用此代码调用该方法的人实际上不会执行该方法:

using(SqlDataReader rd = cmd.ExecuteReader()){
while(rd.Read())
yield return rd.ConvertTo<T>(); //extension method wrapping FastMember
}

但是当他们执行返回的IEnumerable<>时,using块打开,直到IEnumerable<>完成迭代才会Dispose(),此时您已经从数据读取器读取了所需的一切。

这是因为"yield return"将返回一个元素并继续迭代,而"正常"返回将完成调用。

最新更新