c# - yield return vs. return IEnumerable<T> -
i've noticed curious reading idatareader within using statement can't comprehend. though i'm sure answer simple.
why whilst inside using (sqldatareader rd) { ... } if directly perform yield return reader stays open duration of read. if perform direct return calling sqldatareader extension method (outlined below) reader closes before enumerable can actualized?
public static ienumerable<t> enumerate<t>(this sqldatareader rd) { while (rd.read()) yield return rd.convertto<t>(); //extension method wrapping fastmember rd.nextresult(); } to absolutely clear of i'm asking, i'm unsure why following fundamentally different:
a fleshed out example, per @timschmelter's request:
/* * 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 read when reader closed }
summary: both versions of method defer because
readsomeprocextdoesn't defer execution, reader disposed before execution passed caller (i.e. beforeenumerate<t>can run).readsomeprocon other hand doesn't create reader until it's been passed caller, doesn't dispose container until value have been read.
when method uses yield return, compiler changes compiled code return ienumerable<>, , the code in method not run until other code starts iterating on returned ienumerable<>.
that means code below doesn't run first line of enumerate method before disposes reader , returns value. time else starts iterating on returned ienumerable<>, reader has been disposed.
using(sqldatareader rd = cmd.executereader()){ return rd.enumerate<t>(); } but code execute entire enumerate() method in order produce list<> of results prior returning:
using(sqldatareader rd = cmd.executereader()){ return rd.enumerate<t>().tolist(); } on other hand, whoever's calling method code doesn't execute method until result evaluated:
using(sqldatareader rd = cmd.executereader()){ while(rd.read()) yield return rd.convertto<t>(); //extension method wrapping fastmember } but moment execute returned ienumerable<>, using block opens up, , doesn't dispose() until ienumerable<> finishes iterations, @ point have read need data reader.
Comments
Post a Comment