繁体   English   中英

收益率与收益率IEnumerable相比<T>

[英]yield return vs. return IEnumerable<T>

我注意到在使用语句中读取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
}

简介:该方法的两个版本都推迟 ,但由于ReadSomeProcExt不会延迟执行,因此在执行传递回调用方之前(即在Enumerate<T>可以运行之前)处理读取器。 另一方面, ReadSomeProc在它被传递回调用者之前不会创建读取器,因此它不会在读取所有值之前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块打开,并且它不会Dispose()直到IEnumerable<>完成其迭代,此时您将已经从数据读取器中读取了所需的所有内容。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM