我将提出不同意见。对于特定问题“是否有必要将StreamWriter包装在using块中?”,答案实际上是不需要。事实上,你不应该调用StreamWriter的Dispose方法,因为它的设计存在问题并会导致错误的结果。
StreamWriter的问题在于,在你Dispose它时,它也会Dispose底层流。如果你使用文件名创建StreamWriter,并且它内部创建了自己的FileStream,则此行为完全合适。但是,如果像这里一样,你使用现有的流创建StreamWriter,则这种行为绝对是错误的。但是StreamWriter仍会执行这种行为。
像下面这样的代码将无法正常工作:
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream)) { ... }
stream.Position = 0;
using (var reader = new StreamReader(stream)) { ... }
由于当 StreamWriter 的 using 块释放掉 StreamWriter 时,也会一并丢弃流。所以当您尝试从该流中读取时,就会出现 ObjectDisposedException 异常。
StreamWriter 违反了“自己收拾自己的垃圾”的原则。它试图清理其他人的垃圾,无论他们是否想要这样做。
(想象一下如果您在现实生活中这样做。试着向警察解释为什么您闯入别人家里并开始把所有东西扔进垃圾桶...)
因此,我认为 StreamWriter(和做同样事情的 StreamReader)是极少数几个“如果实现了 IDisposable,则应调用 Dispose”是错误的类之一。不要在已创建基于现有流的 StreamWriter 上调用 Dispose。而是应该调用 Flush()。
然后,只需确保在应该清理流时清理即可。(如 Joe 指出的,ASP.NET 会为您处理 Response.OutputStream 的处理,因此您不需要在此处担心。)
注意:如果您没有对 StreamWriter 进行 Dispose,则在完成写入操作时需要调用 Flush()。否则,可能仍然存在在内存中缓冲的数据,但它永远不会传输到输出流中。
我的 StreamReader 规则是,假装它没有实现 IDisposable。只需在完成时将其放开即可。
我的 StreamWriter 规则是,在您本应调用 Dispose 的地方调用 Flush。(这意味着您必须使用 try..finally 代替 using。)