<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx</link><description>The other day I went to buy some snack from the snack machine in the kitchen. The snack I wanted was in slot B-10, so I put in my coins, press B - one - zero, hey wait a minute there's no zero button! And why is it serving me up the snack on the left</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934311</link><pubDate>Mon, 08 Sep 2008 21:09:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934311</guid><dc:creator>Michael Ratanapintha</dc:creator><description>&lt;p&gt;This is just picking nits, but there may be reasons why you want to give this method a Stream, or a text Reader, instead of a filename. &amp;nbsp;Obvious examples: a socket, a named pipe, a String, or an in-memory buffer.&lt;/p&gt;
&lt;p&gt;Also, I'm somewhat surprised that, as shown in the original, StreamReader even has a BaseStream property. &amp;nbsp;If the StreamReader owns its Stream, then why is the Stream even being exposed for the client to muck around with?&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934439</link><pubDate>Mon, 08 Sep 2008 21:57:40 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934439</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;In the particular case, the code was being used ONLY to read from text files on disk. Better to not be prematurely general, as premature generality got the author of this code into trouble in the first place.&lt;/p&gt;
&lt;p&gt;If you were to design a Lines() method that took an arbitrary reader, it would be a good idea to explicitly document that the returned enumerator owns the reader and will close it when it is done.&lt;/p&gt;
&lt;p&gt;To answer your question -- yes, this is a bit of a leaky abstraction, isn't it? &amp;nbsp;And quite dangerous. &amp;nbsp;But one can imagine situations in which code handed a stream reader might want to interrogate the underlying stream for interesting facts about it before blindly calling the streamreader methods on it -- like &amp;quot;just how big is this stream?&amp;quot;, so that the code could put up a user interface element saying how much more of the stream there was to be processed, and so on.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934453</link><pubDate>Mon, 08 Sep 2008 22:03:44 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934453</guid><dc:creator>configurator</dc:creator><description>&lt;p&gt;I agree with Michael.&lt;/p&gt;
&lt;p&gt;- but -&lt;/p&gt;
&lt;p&gt;The stream can also be used in a much better way, simply by adding a using (reader) around the body of the function. Also, I'd remove the seek, and add an XML comment stating that the function returns the rest of the lines up to the end of the stream, then disposes of it.&lt;/p&gt;
&lt;p&gt;I'd also like to point this out: using 'using' in iterator functions is perfectly unsafe. This is the one scenario that eludes the semantics of 'using'. Whenever we use using, we know that when used 'properly', the object will always be disposed as soon as possible. But when will it dispose if we happen to read only halfway through the file, then break out of the foreach loop, or even throw an exception? It seems that the iterator object would still be alive until GC collects it, wouldn't it? And as long as the iterator object is alive, the function will be stuck in mid-execution, meaning that it would not exit the using block and not dispose of the file. Am I missing something here?&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934510</link><pubDate>Mon, 08 Sep 2008 22:21:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934510</guid><dc:creator>Jonathan Pryor</dc:creator><description>&lt;p&gt;`using` within iterators is safer than you give it credit for.&lt;/p&gt;
&lt;p&gt;If someone uses `foreach' and breaks out of the loop early, the `using' will still work.&lt;/p&gt;
&lt;p&gt;If an exception is generated from the `foreach', the `using' will still work.&lt;/p&gt;
&lt;p&gt;The reason both of these work is because IEnumerator&amp;lt;T&amp;gt; implements IDisposable, and the generated iterator .Dispose() will execute the `finally' block of the `using' statement. &amp;nbsp;Try it; it works.&lt;/p&gt;
&lt;p&gt;The only time that `using' won't work is if you (1) forego `foreach` (i.e. manually reimplement foreach), AND (2) forget to .Dispose() of the iterator.&lt;/p&gt;
&lt;p&gt;Doing both (1) and (2) is possible, but I would suggest that it's not very likely.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934533</link><pubDate>Mon, 08 Sep 2008 22:29:13 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934533</guid><dc:creator>Muhammad</dc:creator><description>&lt;p&gt;Hello Eric,&lt;/p&gt;
&lt;p&gt;thanks much - as always, very interesting post.&lt;/p&gt;
&lt;p&gt;it would be great if you can explain 2 points:&lt;/p&gt;
&lt;p&gt;1- why do you have a private &amp;amp; public interfaces?&lt;/p&gt;
&lt;p&gt;2- and I didn't get your first objection (Namely, the null check is not performed when the method is called)?&lt;/p&gt;
&lt;p&gt;how is the check for null different between original and corrected implementations?&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934537</link><pubDate>Mon, 08 Sep 2008 22:30:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934537</guid><dc:creator>kostat</dc:creator><description>&lt;p&gt;to configurator:&lt;/p&gt;
&lt;p&gt;yes, you are. I asked a very same question, but looked to IL first. IEnumerator&amp;lt;T&amp;gt; is IDisposable, so you should dispose it by contract when you are done and foreach does it correctly. Even though non generic IEnumerator is not IDisposable (BCL flaw), for foreach the compiler does a good job by checking if it 'is' IDisposable.&lt;/p&gt;
&lt;p&gt;Kosta&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934547</link><pubDate>Mon, 08 Sep 2008 22:33:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934547</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;P&gt;Jonathan is correct. Remember, foreach(A b in c) D(b); is actually codegenned as though you had written something like:&lt;/P&gt;
&lt;P&gt;{&lt;BR&gt;&amp;nbsp; E e = c.GetEnumerator();&lt;BR&gt;&amp;nbsp; try &lt;BR&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp; &amp;nbsp; while(e.MoveNext()) { b = (A)e.Current; D(b); }&lt;BR&gt;&amp;nbsp; } &lt;BR&gt;&amp;nbsp; finally &lt;BR&gt;&amp;nbsp; {&lt;BR&gt;&amp;nbsp; &amp;nbsp; e.Dispose();&lt;BR&gt;&amp;nbsp; }&lt;BR&gt;}&lt;/P&gt;
&lt;P&gt;Disposing an enumerator causes any not-yet-run finally blocks in the iterator block to run.&lt;/P&gt;
&lt;P&gt;So in both the cases you describe, the reader would be disposed immediately upon prematurely leaving the foreach, whether via exception, break, goto, or return.&lt;/P&gt;</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934562</link><pubDate>Mon, 08 Sep 2008 22:36:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934562</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;P&gt;Muhammad:&lt;/P&gt;
&lt;P&gt;1) The public method checks its argument. The private method does not. &amp;nbsp;Don't expose two methods which do the same thing, but where one is safe and the other is dangerous.&lt;/P&gt;
&lt;P&gt;2) Since the iterator block does not run until the first MoveNext, the check for null doesn't happen until possibly long after the call to Lines(). &amp;nbsp;You want the check to happen immediately so that if it is going to fail, it fails at the earliest possible point.&amp;nbsp; That is, consider the original code called like this:&lt;/P&gt;
&lt;P&gt;StreamReader&amp;nbsp;reader = null;&lt;BR&gt;var lines = reader.Lines(); // you expect it to throw here&lt;BR&gt;// ...&lt;BR&gt;foreach(var line in lines) // but it actually throws here, because the iterator block doesn't run until the first MoveNext. This could be in completely different code and long after the call to Lines(), which is confusing.&lt;/P&gt;</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934573</link><pubDate>Mon, 08 Sep 2008 22:39:31 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934573</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;Now, in the interests of full disclosure, note that this is &amp;quot;unsafe&amp;quot; in the sense that we have many times shipped bugs where the codegen for some cases does not correctly run the finally blocks when something disposes of an iterator halfway through. &amp;nbsp;The codegen for these cases is the single hardest part of the compiler and we've screwed it up in the past. For example, there were cases with nested finally blocks where the finally blocks would run in the wrong order.&lt;/p&gt;
&lt;p&gt;If anyone finds such bugs in the service release of the compiler, PLEASE tell me about them.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934587</link><pubDate>Mon, 08 Sep 2008 22:44:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934587</guid><dc:creator>RichB</dc:creator><description>&lt;p&gt;Wow - you managed to say all of that without once mentioning 'invariant' :-)&lt;/p&gt;
&lt;p&gt;BTW - any reason for inferring the type of 'reader' using 'var', while you declared 'line' directly as a string? What reasoning did you have for declaring the two variables in different ways?&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934596</link><pubDate>Mon, 08 Sep 2008 22:49:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934596</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;RichB: It is dead obvious from the initialization of reader what the type will be. The &amp;quot;new StreamReader&amp;quot; sitting right there tells you what the type is. Stating the type is completely redundant for reader.&lt;/p&gt;
&lt;p&gt;But it is not obvious from just the initialization of &amp;quot;line&amp;quot; that it will be a string. In that case you have to know what type ReadLine returns. By stating &amp;quot;string&amp;quot; explicitly it makes it obvious to the reader that my intention was for this thing to be a string.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934644</link><pubDate>Mon, 08 Sep 2008 23:08:07 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934644</guid><dc:creator>Jonathan Pryor</dc:creator><description>&lt;p&gt;As for the original design of Lines(), my biggest beef is that it mucks around with .BaseStream, which is evil (for all the reasons mentioned).&lt;/p&gt;
&lt;p&gt;My 2nd beef, though, isn't mentioned: .Lines() is on StreamReader.&lt;/p&gt;
&lt;p&gt;It _should_ be on TextReader, which would allow us to do:&lt;/p&gt;
&lt;p&gt;foreach (var line in Console.In.Lines ()) { ... }&lt;/p&gt;
&lt;p&gt;Which just seems perfectly natural to me.&lt;/p&gt;
&lt;p&gt;Which further makes things more complicated about the `ownership` argument: .Lines() certainly should NOT be disposing of Console.In when it's complete, as Console.In is managed by the runtime.&lt;/p&gt;
&lt;p&gt;Which says to me that .Lines() shouldn't &amp;quot;own&amp;quot; the TextReader, at least not by default.&lt;/p&gt;
&lt;p&gt;I'm also not sure it's a &amp;quot;leaky abstraction,&amp;quot; either, as all .Lines() is documented to do is extract lines of text from the input, NOT to actually own the input (as it may be ideal to reuse the existing StreamReader instead of creating a new one).&lt;/p&gt;
&lt;p&gt;(As for &amp;quot;Readers are cheap,&amp;quot; I'm not entirely sure of that, unless you also argue that HANDLEs are cheap. &amp;nbsp;Since a StreamReader owns the underlying Stream, and a Stream is a kernel HANDLE to a file, by definition multiple readers will require multiple kernel HANDLEs. &amp;nbsp;Plus you'll need to provide the appropriate flags to the FileStream constructor, lest you only be able to have *one* FileStream open for that file (the FileShare enumeration), which would kill your &amp;quot;multiple readers&amp;quot; defense rather quickly...)&lt;/p&gt;
&lt;p&gt;I think there is one problem most apparent, though: FileUtilities.Lines() shouldn't be necessary. &amp;nbsp;In particular, File.ReadAllLines() should have done this in the first place! &amp;nbsp;Who's brilliant idea was it to make File.ReadAllLines() return a string[]? &amp;nbsp;That design decision restricts any actual improvement in that method, AND requires that the entire file be loaded into memory at once. &amp;nbsp;Brillant!&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8934790</link><pubDate>Mon, 08 Sep 2008 23:47:23 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8934790</guid><dc:creator>Rik Hemsley</dc:creator><description>&lt;p&gt;Really nice rewrite of the original code. I'd be proud if I'd done the same.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8935065</link><pubDate>Tue, 09 Sep 2008 01:31:35 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8935065</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;Well, again, it comes down to &amp;quot;premature generalization is evil&amp;quot;. The purpose of the code was &amp;quot;open a bunch of files for reading and read them in one line at a time&amp;quot;, and when you write code that implements something more general than that, then you have all the design, implementation and testing burden of ensuring that your system works with ANYTHING that can be a TextReader instead of merely anything that can be a file name. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;If you wanted this system to work on arbitrary text readers then you would need to decide and document who owns the thing and whether or not it is closed when you're done reading; if you need to impose the tax of the caller keeping ownership of the reader then that's a consequence of having to solve the more general problem. Generality is expensive, and therefore to be avoided if it cannot be made cheap.&lt;/p&gt;
&lt;p&gt;As for the design flaw in &amp;quot;lines&amp;quot; in the first place -- you will get no argument from me. I have a separate rant queued up about methods that return arrays. However, keep in mind that this method was invented before generic types were added to the CLR. Obviously today you would use IEnumerable&amp;lt;string&amp;gt;, but in CLR v1, that was not an option.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8935331</link><pubDate>Tue, 09 Sep 2008 03:07:08 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8935331</guid><dc:creator>Jonathan Pryor</dc:creator><description>&lt;p&gt;The method may have been *designed* before CLR v2.0 (who's to say for sure outside of Microsoft?), but it wasn't *introduced* until .NET 2.0:&lt;/p&gt;
&lt;p&gt;&lt;a rel="nofollow" target="_new" href="http://msdn.microsoft.com/en-us/library/s2tte0y1.aspx"&gt;http://msdn.microsoft.com/en-us/library/s2tte0y1.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;quot;Supported in: 3.5, 3.0, 2.0&amp;quot;&lt;/p&gt;
&lt;p&gt;Even if it were in 1.0/1.1, it could have returned an IEnumerable, which would allow future alteration of the method's implementation, as opposed to (effectively) leaking implementation details to one and all. &amp;nbsp;Alas, this wouldn't be strongly typed, but it would allow migrating the implementation from an array-based to a C# iterator based implementation. &amp;nbsp;The only downside is you lose type safety. :-(&lt;/p&gt;
&lt;p&gt;(You also lose array indexing, which makes it ~trivial to write out a line along with it's corresponding line number. &amp;nbsp;Providing the line number is easy without arrays, but not _as_ easy.)&lt;/p&gt;
&lt;p&gt;(I think this would also be in keeping with the FxDG: Section 5.7 says &amp;quot;DO use the least derived parameter type that provides the functionality required by the member.&amp;quot; &amp;nbsp;A return type isn't a parameter, but I believe the the same basic idea holds true: return the type that provides you the greatest future flexibility. &amp;nbsp;string[] has _no_ future flexibility, while IEnumerable does.)&lt;/p&gt;
&lt;p&gt;iirc, there are several other methods added in 2.0 which return non-generic types where it really would have made more sense. &amp;nbsp;It seems that not everyone got the `C# iterator` love memo (while LINQ is predecated upon lots of C# iterator love, so I guess that makes up for it).&lt;/p&gt;
&lt;p&gt;(Furthermore, many v1.0 types haven't been retrofited to support the v2.0 generic interfaces, e.g XmlNodeList.)&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8935414</link><pubDate>Tue, 09 Sep 2008 03:39:59 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8935414</guid><dc:creator>peted</dc:creator><description>&lt;p&gt;I agree with the general sentiment. &amp;nbsp;But I do take issue with a couple of comments:&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;&amp;quot; No one should be messing with that stream but the reader.&amp;quot;&lt;/p&gt;
&lt;p&gt;Well, for better or worse, .NET is specifically advertising this as a feature. &amp;nbsp;The StreamReader provides no API itself to manage position within the stream, does provide the BaseStream property as well as the DiscardBufferedData method. &amp;nbsp;The intent of the contract for StreamReader is clearly to allow random-access to the stream, and to do so by virtue of allowing the client of the StreamReader to manage the position, rather than having the StreamReader itself do it.&lt;/p&gt;
&lt;p&gt;I suppose you could argue that the .NET design is flawed. &amp;nbsp;But it is what it is, and when used carefully there's nothing inherently wrong with this use of StreamReader.&lt;/p&gt;
&lt;p&gt;Also:&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;&amp;quot;Maybe the caller knows that there are a bunch of bytes that it wants to skip, so it deliberately hands a StreamReader to Lines() which has been positioned somewhere past the beginning of the file. But Lines() thinks that it knows best and ignores the information that the caller has given it.&amp;quot;&lt;/p&gt;
&lt;p&gt;As an interface goes, imperfect perhaps. &amp;nbsp;But I don't see anything fundamentally wrong with the contract. &amp;nbsp;At worst, perhaps the method should have been named &amp;quot;AllLines&amp;quot; instead. &amp;nbsp;The author could even have provided an additional &amp;quot;RemainingLines&amp;quot;.&lt;/p&gt;
&lt;p&gt;I do agree that the proposed fully-encapsulated version is much better, and that by hiding the stream and the reader altogether, it fully avoids interference and strange side-effects from the client code, which is a good thing. &amp;nbsp;But coding isn't black and white, and I think there's room for imperfect implementations, when used appropriately.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8935428</link><pubDate>Tue, 09 Sep 2008 03:47:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8935428</guid><dc:creator>Brandon Bloom</dc:creator><description>&lt;p&gt;If you take a file name instead of an open file, your contract now includes a significant number of IO and security exceptions which could be raised...&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8935676</link><pubDate>Tue, 09 Sep 2008 05:50:35 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8935676</guid><dc:creator>Jonathan Pryor</dc:creator><description>&lt;p&gt;And as an added bonus, the FileUtilities.Lines(string) version is harder to unit test, as it requires that a well-known file exist in a well-known location.&lt;/p&gt;
&lt;p&gt;The .Lines(StreamReader) suffers from the same problem.&lt;/p&gt;
&lt;p&gt;A .Lines(TextReader) version is quite easy to unit test, as you can pass it a StringReader to verify that it behaves the way you think it behaves (as long as StringReader and StreamReader follow the TextReader contract, which they should do...).&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936226</link><pubDate>Tue, 09 Sep 2008 12:26:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936226</guid><dc:creator>Ollie Riches</dc:creator><description>&lt;p&gt;Another example of how not to use extension methods may be?&lt;/p&gt;
&lt;p&gt;As for comments about Eric's implmentation taking a filename (path) and not a stream based reader - Eric's version encapsulates the file manipulation completely and abstracts the caller away from knowing how the file is being manipulated.&lt;/p&gt;
&lt;p&gt;Also I don't see any issue with unit testing this either...&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936289</link><pubDate>Tue, 09 Sep 2008 13:06:35 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936289</guid><dc:creator>Senthil Kumar</dc:creator><description>&lt;p&gt;There's another reason why the original code did a seek to 0. If it didn't, then the following piece of code would have printed false.&lt;/p&gt;
&lt;p&gt;var lines = someStreamReader.Lines();&lt;/p&gt;
&lt;p&gt;Console.WriteLine(lines.First() == lines.First())&lt;/p&gt;
&lt;p&gt;All constructed enumerators would have referenced the same stream, so advancing one would have advanced all of them.&lt;/p&gt;
&lt;p&gt;Eric's implementation avoids the problem by constructing a new StreamReader inside the method.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936365</link><pubDate>Tue, 09 Sep 2008 14:04:17 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936365</guid><dc:creator>rbirkby</dc:creator><description>&lt;p&gt;&amp;gt; &amp;quot; No one should be messing with that stream but the reader.&amp;quot;&lt;/p&gt;
&lt;p&gt;Or to put it another way - the &amp;quot;Inappropriate intimacy&amp;quot; Code Smell.&lt;/p&gt;
&lt;p&gt;&lt;a rel="nofollow" target="_new" href="http://en.wikipedia.org/wiki/Code_smell"&gt;http://en.wikipedia.org/wiki/Code_smell&lt;/a&gt;&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936627</link><pubDate>Tue, 09 Sep 2008 16:50:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936627</guid><dc:creator>stefan.wenig</dc:creator><description>&lt;p&gt;Eric, &lt;/p&gt;
&lt;p&gt;you've just made a great case for generators in lambda expressions!&lt;/p&gt;
&lt;p&gt;public static IEnumerable&amp;lt;string&amp;gt; Lines (this StreamReader reader)&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp;if (reader == null)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;throw new ArgumentNullException (&amp;quot;reader&amp;quot;);&lt;/p&gt;
&lt;p&gt; &amp;nbsp;return new EnumerableWrapper&amp;lt;string&amp;gt; (delegate&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;for (; ; )&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;string line = reader.ReadLine ();&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (line == null)&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;yield break;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;yield return line;&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp;});&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Wouldn't it be great if that could compile? (The EnumerableWrapper class would just implement IEnumerable&amp;lt;T&amp;gt; and IEnumerable, and delegate both to the Func&amp;lt;IEnumerable&amp;lt;T&amp;gt;&amp;gt; it receives. Anonymous classes would be another nice thing in this particular situation, but live as we know it doesn't quite end without them.)&lt;/p&gt;
&lt;p&gt;The problem is that argument checking in a generator is a quite common case. What's your answer for that? Don't check those arguments? Manually build a closure class? Create psychic debugging situations?&lt;/p&gt;
&lt;p&gt;I realize this is not quite simple, but still - it would be great, not?&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936751</link><pubDate>Tue, 09 Sep 2008 18:00:39 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936751</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;Indeed, I would love to have anonymous iterators.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936826</link><pubDate>Tue, 09 Sep 2008 18:34:28 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936826</guid><dc:creator>russellh</dc:creator><description>&lt;p&gt;Maybe I'm very old school C, but what is so bad about this line?&lt;/p&gt;
&lt;p&gt;while ((line = reader.ReadLine()) != null)&lt;/p&gt;
&lt;p&gt;It just reads a line from the stream into line and checks for end of stream. &amp;nbsp;Seems obvious to me.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8936846</link><pubDate>Tue, 09 Sep 2008 18:44:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8936846</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;First off, that line of code:&lt;/p&gt;
&lt;p&gt;* calls ReadLine&lt;/p&gt;
&lt;p&gt;* assigns to line&lt;/p&gt;
&lt;p&gt;* checks the value assigned to see if it is null&lt;/p&gt;
&lt;p&gt;* branches&lt;/p&gt;
&lt;p&gt;four things is rather a lot for one line of code to be doing. &lt;/p&gt;
&lt;p&gt;Second, there are five logical conditions that one might want to put a breakpoint immediately before:&lt;/p&gt;
&lt;p&gt;* entering the loop&lt;/p&gt;
&lt;p&gt;* reading the line&lt;/p&gt;
&lt;p&gt;* testing the value&lt;/p&gt;
&lt;p&gt;* finishing the iteration&lt;/p&gt;
&lt;p&gt;* yielding the next value &lt;/p&gt;
&lt;p&gt;In my version there are five different places to put breakpoints, one for each of these. In the original version, there are not.&lt;/p&gt;
&lt;p&gt;Third, sure, any experienced C programmer can easily tell what this does, because it uses a C-style idiom. Why would you use a C-style idiom in C#? Use C# idioms in C#. &amp;nbsp;&lt;/p&gt;
&lt;p&gt;Fourth, just because you CAN write expressions that are terse doesn't mean that there is any virtue to them. &lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8937049</link><pubDate>Tue, 09 Sep 2008 20:17:10 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8937049</guid><dc:creator>peted</dc:creator><description>&lt;p&gt;&amp;quot;Indeed, I would love to have anonymous iterators.&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;lt;drool&amp;gt;&lt;/p&gt;
&lt;p&gt;Me too! &amp;nbsp;Me too! &amp;nbsp;:)&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8937251</link><pubDate>Tue, 09 Sep 2008 22:09:18 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8937251</guid><dc:creator>Brian O</dc:creator><description>&lt;p&gt;Nice post, Eric.&lt;/p&gt;
&lt;p&gt;What do you think about adding the below check after the null argument test in Line(). &amp;nbsp;&lt;/p&gt;
&lt;p&gt;if (!File.Exists(filename)) &lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;throw new FileNotFoundException(&amp;quot;File does not exists&amp;quot;, filename);&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Pros: &amp;nbsp; Exception is thrown closer to the error&lt;/p&gt;
&lt;p&gt;Cons: &amp;nbsp;Localization requirment if the constructor(string message, string filename) is used.&lt;/p&gt;
&lt;p&gt;(side note: It would be nice if the FileNotFoundException constructor accepted a file path as the only argument, like the ArgumentNullException type. &amp;nbsp;This would make a little nicer error message without having a localization burden.)&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8939162</link><pubDate>Wed, 10 Sep 2008 08:59:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8939162</guid><dc:creator>Bahador</dc:creator><description>&lt;p&gt;Suppose the actual iteration of Lines() spans over a large period of time, and we don't want to maintain a lock on the file in the whole process.&lt;/p&gt;
&lt;p&gt;Will you consider the method's contract clear if it was implemented the following way.&lt;/p&gt;
&lt;p&gt;Specifically, is it better to writing the method this way, or we must give the caller the burden of first iterating over all the lines and cache them to use later?&lt;/p&gt;
&lt;p&gt;	public static class FileUtilities&lt;/p&gt;
&lt;p&gt;	{&lt;/p&gt;
&lt;p&gt;		public static IEnumerable&amp;lt;string&amp;gt; Lines(string filename)&lt;/p&gt;
&lt;p&gt;		{&lt;/p&gt;
&lt;p&gt;			if (filename == null)&lt;/p&gt;
&lt;p&gt;				throw new ArgumentNullException(&amp;quot;filename&amp;quot;);&lt;/p&gt;
&lt;p&gt;			Debug.Assert(filename != null);&lt;/p&gt;
&lt;p&gt;			List&amp;lt;string&amp;gt; s = new List&amp;lt;string&amp;gt;();&lt;/p&gt;
&lt;p&gt;			using (var reader = new StreamReader(filename))&lt;/p&gt;
&lt;p&gt;			{&lt;/p&gt;
&lt;p&gt;				while (true)&lt;/p&gt;
&lt;p&gt;				{&lt;/p&gt;
&lt;p&gt;					string line = reader.ReadLine();&lt;/p&gt;
&lt;p&gt;					if (line == null)&lt;/p&gt;
&lt;p&gt;						break;&lt;/p&gt;
&lt;p&gt;					s.Add(line);&lt;/p&gt;
&lt;p&gt;				}&lt;/p&gt;
&lt;p&gt;			}&lt;/p&gt;
&lt;p&gt;			return s;&lt;/p&gt;
&lt;p&gt;		}&lt;/p&gt;
&lt;p&gt;	}&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8939527</link><pubDate>Wed, 10 Sep 2008 11:37:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8939527</guid><dc:creator>[ICR]</dc:creator><description>&lt;p&gt;I think by virtue of being an extension method the original has no obligation to clean up. I wouldn't expect a call to theStream.Method() to dispose of the stream. Of course that doesn't discount the issue of altering the stream, but without that I think the contract is then perfectly clear.&lt;/p&gt;
&lt;p&gt;(For a precedence see ReadToEnd)&lt;/p&gt;
&lt;p&gt;Though I would agree about not being too generic from the beginning.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8941825</link><pubDate>Wed, 10 Sep 2008 22:57:24 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8941825</guid><dc:creator>Sebastien Lorion</dc:creator><description>&lt;p&gt;I am surprised no one commented on the name of the method. &amp;quot;Lines&amp;quot; ... lines what? That tells me nothing about what the method does, I can only guess it by looking at its signature. I am a big proponent of method names being verbs and class names being nouns.&lt;/p&gt;
&lt;p&gt;I also agree with some others that the method should work on TextReader. For me, the version using filename is just icing on the cake as it is probably the most common operation. Anyway, it all depends on the context where this class is used.&lt;/p&gt;
&lt;p&gt;&amp;quot;[...] you have all the design, implementation and testing burden of ensuring that your system works with ANYTHING that can be a TextReader [...]&amp;quot;&lt;/p&gt;
&lt;p&gt;Can you elaborate on that? As long as implementations of a TextReader respect its contract, I don't understand why you would impose on yourself such a burden, so I am curious to know your reasons for saying that.&lt;/p&gt;
</description></item><item><title>What's wrong with this code, part II</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8944197</link><pubDate>Thu, 11 Sep 2008 12:51:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8944197</guid><dc:creator>Steve Strong's Blog</dc:creator><description>&lt;p&gt;What's wrong with this code, part II&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8945526</link><pubDate>Fri, 12 Sep 2008 00:22:56 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8945526</guid><dc:creator>Sebastien Lorion</dc:creator><description>&lt;p&gt;About the &amp;quot;while ((line = reader.ReadLine()) != null)&amp;quot; line, we would not need such a hack or the awkward code you posted if the method was better designed, for example:&lt;/p&gt;
&lt;p&gt;bool ReadLine(out string line)&lt;/p&gt;
&lt;p&gt;which gives&lt;/p&gt;
&lt;p&gt;string line;&lt;/p&gt;
&lt;p&gt;while (reader.ReadLine(out line))&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp;yield return line;&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8948228</link><pubDate>Sat, 13 Sep 2008 00:39:24 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8948228</guid><dc:creator>Brennan</dc:creator><description>&lt;p&gt;I disagree with the &amp;quot;ownership&amp;quot; idea in this case and in many Stream scenarios similar to this. BinaryReader &amp;quot;correctly&amp;quot; takes ownership of the stream and closes the stream when you're done with the BinaryReader. But sometimes you just need BinaryReader functionality for a subset of the stream. If that's you're secenario you're out of luck--you have to reimplement BinaryReader! That's the greater of the evils.&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8948313</link><pubDate>Sat, 13 Sep 2008 01:28:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8948313</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;P&gt;So Brennan, your suggestion is that the frameworks designers ought to make the 99% likely common case difficult and bug-prone so that the 1% rare case works more easily?&lt;/P&gt;
&lt;P&gt;An important principle of frameworks design is that the people doing weird stuff should be the ones writing the goofy code. The people doing normal stuff should be given implementations that are not bug-prone.&lt;/P&gt;
&lt;P&gt;That said, I also&amp;nbsp;disagree completely with your claim that the only alternative is to reimplement the reader. Were I faced with such a 1% scenario, I'd just implement a thin "no dispose stream" that wraps the underlying stream, but does not pass along the call to dispose. You want to make a binary reader that doesn't dispose the stream, you just wrap the stream in your 'no dispose wrapper' and hand that thing to the reader. When the reader disposes the stream, that's a no-op and the underlying stream lives on. That seems a lot easier than re-implementing the reader.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description></item><item><title>Weekly Web Nuggets #29</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8952068</link><pubDate>Mon, 15 Sep 2008 06:03:16 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8952068</guid><dc:creator>Code Monkey Labs</dc:creator><description>&lt;p&gt;General Comparing .NET IoC Frameworks Part 1 : Andrey Shchekin takes a look at 6 of the most popular IoC frameworks available for .NET. Comparing .NET IoC Frameworks Part 2 : The continuation of Andrey Shchekin's IoC shootout. High Maintenance Code :&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8956358</link><pubDate>Thu, 18 Sep 2008 02:25:42 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8956358</guid><dc:creator>Greg </dc:creator><description>&lt;p&gt;I'd discourage this type of code in production systems for maintainablity reasons as it fails the Monday morning, I did not get any sleep the night before and my brain is dead, code understandable test.&lt;/p&gt;
&lt;p&gt;It hides its purpose which is to facilitate forward movement line by line through a text file.&lt;/p&gt;
&lt;p&gt;Cute code like this is OK when used one or a few times in an application, but damages the maintainability of a large application with many hundred of different examples of cute tricky code. &amp;nbsp;&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8961650</link><pubDate>Tue, 23 Sep 2008 01:44:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8961650</guid><dc:creator>Chuck Enders</dc:creator><description>&lt;p&gt;Excellent discussion.&lt;/p&gt;
&lt;p&gt;Please don't let the pointy-haired boss have the last word.&lt;/p&gt;
</description></item><item><title>High maintenance code</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8961908</link><pubDate>Tue, 23 Sep 2008 07:20:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8961908</guid><dc:creator>DotNetKicks.com</dc:creator><description>&lt;p&gt;You've been kicked (a good thing) - Trackback from DotNetKicks.com&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8963345</link><pubDate>Wed, 24 Sep 2008 11:22:48 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8963345</guid><dc:creator>stefan.wenig</dc:creator><description>&lt;p&gt;Somehow my comment was lost. I like your solution so much that I documented it as a pattern, see community content at &lt;a rel="nofollow" target="_new" href="http://msdn.microsoft.com/en-us/library/65zzykke.aspx"&gt;http://msdn.microsoft.com/en-us/library/65zzykke.aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;cheers&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8963677</link><pubDate>Wed, 24 Sep 2008 17:44:45 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8963677</guid><dc:creator>Eric Lippert</dc:creator><description>&lt;p&gt;Nice, thanks!&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8970332</link><pubDate>Tue, 30 Sep 2008 17:25:53 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8970332</guid><dc:creator>Richard</dc:creator><description>&lt;p&gt;A StreamReader / StreamWriter taking ownership of a Stream just seems wrong. Methods and classes should not be responsible for cleaning up resources that they didn't create, unless this is clearly documented and obvious.&lt;/p&gt;
&lt;p&gt;For example, the following looks like it should work, but fails unexpectedly with an ObjectDisposedException on the call to Seek:&lt;/p&gt;
&lt;p&gt;using (var s = new MemoryStream(capacity))&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;using (var writer = new StreamWriter(s))&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Render(writer);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;s.Seek(0L, SeekOrigin.Begin);&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;using (var reader = new StreamReader(s))&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return reader.ReadToEnd();&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;Since the caller created the Stream, it should be the caller's responsibility to close it.&lt;/p&gt;
</description></item><item><title>Blog Carnival #6</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#8970722</link><pubDate>Wed, 01 Oct 2008 00:12:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8970722</guid><dc:creator>IHateSpaghetti {code}</dc:creator><description>&lt;p&gt;In this carnival there&amp;amp;#39;re a lot of software design/patterns and frameworks a bit of SOA, UML, DSL&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#9060454</link><pubDate>Tue, 11 Nov 2008 19:37:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9060454</guid><dc:creator>Stephen</dc:creator><description>&lt;p&gt;I know this is an old topic but I'm really confused regarding why a reader or writer should close the stream itself..&lt;/p&gt;
&lt;p&gt;If I had to create a reader or writer in a way that the reader had to aquire the stream itself, then I would expect the reader to handle cleaning it.. but personally I don't see the readers job as aquiring the stream.. I see that as maybe helper methods.&lt;/p&gt;
&lt;p&gt;It makes completely sense that the solution should be&lt;/p&gt;
&lt;p&gt;using(var stream = .. aquire stream ..) &lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp;using(var reader = new StreamReader(stream))&lt;/p&gt;
&lt;p&gt; &amp;nbsp;{&lt;/p&gt;
&lt;p&gt; &amp;nbsp; &amp;nbsp;.. do stuff..&lt;/p&gt;
&lt;p&gt; &amp;nbsp;}&lt;/p&gt;
&lt;p&gt; &amp;nbsp;stream.Close();&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;I certainly wouldn't be expecting the stream to close the stream.. the reader didn't get the stream, I gave it the stream, so I will dispose the stream as well, thats my contract in the code...&lt;/p&gt;
&lt;p&gt;It seems to go against seperation of concerns, reader becomes somewhat of a 'jack of all trades'.. hey guy don't worry - I'll close the stream when you're done, because thats generally what you want no? &lt;/p&gt;
&lt;p&gt;The code I wrote makes much more sense.. whos doing what.. I'm getting a stream.. I'm reading over the stream.. I'm closing/disposing the stream..&lt;/p&gt;
&lt;p&gt;I agree changing .net now is impossible, the amount of code written thats now expecting this behavior.. but I'd go as far as classifying this in the relms of the clr array.. oh did you guys know i do unsafe invariance as covariance as well? (echoing off)&lt;/p&gt;
&lt;p&gt;nooooooooooooo!&lt;/p&gt;
</description></item><item><title>A nasality talisman for the sultana analyst</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#9396778</link><pubDate>Thu, 05 Feb 2009 00:52:51 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9396778</guid><dc:creator>Fabulous Adventures In Coding</dc:creator><description>&lt;p&gt;The other day my charming wife Leah and I were playing Scrabble Brand Crossword Game (a registered trademark&lt;/p&gt;
</description></item><item><title>re: High maintenance</title><link>http://blogs.msdn.com/ericlippert/archive/2008/09/08/high-maintenance.aspx#9469679</link><pubDate>Wed, 11 Mar 2009 00:17:08 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9469679</guid><dc:creator>Jacco</dc:creator><description>&lt;P&gt;Hi Eric,&lt;/P&gt;
&lt;P&gt;Sorry to respond to such an old post. I was triggered to go here from your Scrabble post :-)&lt;/P&gt;
&lt;P&gt;I am working on an extension library (nxl on codeplex) and am struggling with this one. I came up with the following code but am not sure if its very usable:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;public static IEnumerable&amp;lt;string&amp;gt; StreamLines(Func&amp;lt;Stream&amp;gt; streamConstructor)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;using (Stream stream = streamConstructor()) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;using (var sr = new StreamReader(stream))&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while (true)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string line = sr.ReadLine();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (line == null)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield break;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;yield return line;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/P&gt;
&lt;P&gt;The ownership issue is solved this way but usage is a bit clunky:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;foreach (string line in StreamExtensions.StreamLines(() =&amp;gt; File.Open("C:\test.txt", FileMode.OpenRead)))&lt;/P&gt;
&lt;P&gt;It not even an extension any more :S&lt;/P&gt;
&lt;P&gt;Does it make sense to go this road?&lt;/P&gt;
&lt;P&gt;Regards, Jacco&lt;/P&gt;
&lt;DIV class=yellowbox&gt;
&lt;P&gt;Ah, you are using lambdas to implement lazy evaluation of the stream opening. Is that so that if someone takes out an enumerator and then sits on it without moving it, the file open doesn't happen until the first line is requested? That's pretty clever. A bit clunky, and perhaps a bit TOO clever, but neat. I like it from the point of view of a mechanism that solves this problem.&lt;/P&gt;
&lt;P&gt;However, from a usability standpoint, it's pretty taxing. If the method "StreamLines" is intended to take a stream and return some lines then it should &lt;STRONG&gt;take a stream and return some lines&lt;/STRONG&gt;. Your "lazy evaluation" feature imposes a "tax" on ALL users of this method, not just the users who want to take advantage of the feature. &lt;/P&gt;
&lt;P&gt;What I might do in this case is write two extension methods, one that takes a stream, one that takes a func&amp;lt;stream&amp;gt;. Then you can decide which one you want to use and don't have to pay a tax if you don't want laziness. &lt;/P&gt;
&lt;P&gt;Another way to attack the problem would be to make a new subtype of Stream called LazyStream. A LazyStream takes your Func&amp;lt;Stream&amp;gt;, and then forwards all calls to the lazy evaluated stream when asked. The user can then create a LazyStream if they want to have a stream that isn't opened until its needed.&lt;/P&gt;
&lt;P&gt;-- Eric&lt;/P&gt;&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description></item></channel></rss>