C# 是否有必要将 StreamWriter 包装在 using 块中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1018963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it necessary to wrap StreamWriter in a using block?
提问by Eric
A few days ago I posted some code like this:
几天前,我发布了一些这样的代码:
StreamWriter writer = new StreamWriter(Response.OutputStream);
writer.WriteLine("col1,col2,col3");
writer.WriteLine("1,2,3");
writer.Close();
Response.End();
I was told that instead I should wrap StreamWriter in a using block in case of exceptions. Such a change would make it look like this:
有人告诉我,如果出现异常,我应该将 StreamWriter 包装在 using 块中。这样的更改将使它看起来像这样:
using(StreamWriter writer = new StreamWriter(Response.OutputStream))
{
writer.WriteLine("col1,col2,col3");
writer.WriteLine("1,2,3");
writer.Close(); //not necessary I think... end of using block should close writer
}
Response.End();
I am not sure why this is a valuable change. If an exception occurred without the using block, the writer and response would still be cleaned up, right? What does the using block gain me?
我不确定为什么这是一个有价值的改变。如果在没有 using 块的情况下发生异常,编写器和响应仍然会被清理,对吗?使用块对我有什么好处?
采纳答案by kemiller2002
Nope the stream would stay open in the first example, since the error would negate the closing of it.
不,在第一个示例中流将保持打开状态,因为错误会否定它的关闭。
The using operator forces the calling of Dispose() which is supposed to clean the object up and close all open connections when it exits the block.
using 操作符强制调用 Dispose(),当它退出块时,它应该清理对象并关闭所有打开的连接。
回答by Nick
If an exception occurs without the using block and kills the program, you will be left with openconnections. The using block will always close the connection for you, similiar to if you were to use try{}catch{}finally{}
如果在没有 using 块的情况下发生异常并杀死程序,您将留下 openconnections。using 块将始终为您关闭连接,类似于如果您要使用 try{}catch{}finally{}
回答by Jamie Ide
In my opinion it's necessary to wrap any class that implements IDisposable in a using block. The fact that a class implements IDisposable means that the class has resources that need to be cleaned up.
在我看来,有必要在 using 块中包装任何实现 IDisposable 的类。类实现 IDisposable 的事实意味着该类具有需要清理的资源。
回答by Robert
the using block calls dispose() when it ends. It's just a handy way of ensuring that resources are cleaned up in a timely manner.
using 块在结束时调用 dispose()。这只是确保及时清理资源的一种便捷方式。
回答by John Saunders
In almost every case, if a class implements IDisposable, and if you're creating an instance of that class, then you need the using block.
在几乎所有情况下,如果一个类实现了 IDisposable,并且您正在创建该类的实例,那么您需要 using 块。
回答by Adam Wright
Eventually, the writer will be cleaned up. When this happens is up to the garbage collector, who will notice that the Dispose for the command has not been called, and invoke it. Of course, the GC may not run for minutes, hours or days depending on the situation. If the writer is holding an exclusive lock on say, a file, no other process will be able to open it, even though you're long finished.
最终,作者将被清理。发生这种情况时由垃圾收集器决定,垃圾收集器会注意到尚未调用该命令的 Dispose,并调用它。当然,根据情况,GC 可能不会运行几分钟、几小时或几天。如果作者持有一个排他锁,比如说一个文件,那么没有其他进程能够打开它,即使你已经完成了很长时间。
The using block ensures the Dispose call is always made, and hence that the Close is always called, regardless of what control flow occurs.
using 块确保始终进行 Dispose 调用,因此无论发生什么控制流,始终调用 Close。
回答by Fredrik M?rk
Wrapping the StreamWriter
in a using
block is pretty much equivalent of the following code:
将 包裹StreamWriter
在一个using
块中几乎等同于以下代码:
StreamWriter writer;
try
{
writer = new StreamWriter(Response.OutputStream);
writer.WriteLine("col1,col2,col3");
writer.WriteLine("1,2,3");
}
catch
{
throw;
}
finally
{
if (writer != null)
{
writer.Close();
}
}
While you could very well write this code yourself, it is so much easier to just put it in a using block.
虽然您可以很好地自己编写此代码,但将它放在 using 块中要容易得多。
回答by n8wrl
My rule of thumb is, if I see Dispose listed in intellisense, I wrap it in a using block.
我的经验法则是,如果我在智能感知中看到 Dispose,我会将它包装在 using 块中。
回答by Joe
While it's good practice to always dipose disposable classes such as StreamWriter, as others point out, in this case it doesn't matter.
虽然正如其他人指出的那样,始终部署诸如 StreamWriter 之类的一次性类是一种很好的做法,但在这种情况下并不重要。
Response.OutputStream will be disposed by the ASP.NET infrastructure when it's finished processing your request.
Response.OutputStream 将在 ASP.NET 基础结构完成处理您的请求后进行处理。
StreamWriter assumes it "owns" a Stream passed to the constructor, and will therefore Close the stream when it's disposed. But in the sample you provide, the stream was instantiated outside your code, so there will be another owner who is responsible for the clean-up.
StreamWriter 假定它“拥有”传递给构造函数的 Stream,因此在处理它时将关闭该流。但是在您提供的示例中,流是在您的代码之外实例化的,因此将有另一个所有者负责清理。
回答by Joe White
I'm going to give the dissenting opinion. The answer to the specific question "Is it necessary to wrap StreamWriter in a using block?" is actually No.In fact, you should notcall Dispose on a StreamWriter, because its Dispose is badly designed and does the wrong thing.
我来发表反对意见。特定问题的答案“是否有必要将 StreamWriter 包装在 using 块中?” 实际上不是。事实上,你不应该在 StreamWriter 上调用 Dispose,因为它的 Dispose 设计得很糟糕并且做错了事情。
The problem with StreamWriter is that, when you Dispose it, it Disposes the underlying stream. If you created the StreamWriter with a filename, and it created its own FileStream internally, then this behavior would be totally appropriate. But if, as here, you created the StreamWriter with an existing stream, then this behavior is absolutely The Wrong Thing(tm). But it does it anyway.
StreamWriter 的问题在于,当您处理它时,它会处理底层流。如果您使用文件名创建了 StreamWriter,并且它在内部创建了自己的 FileStream,那么这种行为将是完全合适的。但是,如果像这里一样,您使用现有流创建了 StreamWriter,那么这种行为绝对是错误的事情 (tm)。但无论如何它都会这样做。
Code like this won't work:
像这样的代码不起作用:
var stream = new MemoryStream();
using (var writer = new StreamWriter(stream)) { ... }
stream.Position = 0;
using (var reader = new StreamReader(stream)) { ... }
because when the StreamWriter's using
block Disposes the StreamWriter, that will in turn throw away the stream. So when you try to read from the stream, you get an ObjectDisposedException.
因为当 StreamWriter 的using
块 Dispose StreamWriter 时,这将反过来丢弃流。因此,当您尝试从流中读取时,您会收到 ObjectDisposedException。
StreamWriter is a horrible violation of the "clean up your own mess" rule. It tries to clean up someone else's mess, whether they wanted it to or not.
StreamWriter 严重违反了“清理你自己的烂摊子”规则。它试图清理别人的烂摊子,无论他们是否愿意。
(Imagine if you tried this in real life. Try explaining to the cops why you broke into someone else's house and started throwing all their stuff into the trash...)
(想象一下,如果你在现实生活中尝试过这个。试着向警察解释你为什么闯入别人的房子并开始把他们所有的东西扔进垃圾桶......)
For that reason, I consider StreamWriter (and StreamReader, which does the same thing) to be among the very few classes where "if it implements IDisposable, you should call Dispose" is wrong. Nevercall Dispose on a StreamWriter that was created on an existing stream. Call Flush() instead.
出于这个原因,我认为 StreamWriter(和 StreamReader,它做同样的事情)属于极少数“如果它实现 IDisposable,你应该调用 Dispose”是错误的类。永远不要在现有流上创建的 StreamWriter 上调用 Dispose。改为调用 Flush()。
Then just make sure you clean up the Stream when you should. (As Joe pointed out, ASP.NET disposes the Response.OutputStream for you, so you don't need to worry about it here.)
然后确保在需要的时候清理 Stream。(正如 Joe 指出的,ASP.NET 为您处理了 Response.OutputStream,因此您无需在这里担心。)
Warning: if you don't Dispose the StreamWriter, then you doneed to call Flush() when you're done writing. Otherwise you could have data still being buffered in memory that never makes it to the output stream.
警告:如果您不处置 StreamWriter,那么您在完成写入后确实需要调用 Flush()。否则,您可能仍然在内存中缓冲数据,而这些数据永远不会进入输出流。
My rule for StreamReader is, pretend it doesn't implement IDisposable. Just let it go when you're done.
我对 StreamReader 的规则是,假装它没有实现 IDisposable。完成后就放手吧。
My rule for StreamWriter is, call Flush where you otherwise would have called Dispose. (This means you have to use a try
..finally
instead of a using
.)
我对 StreamWriter 的规则是,调用 Flush 否则你会调用 Dispose。(这意味着您必须使用try
..finally
而不是using
.)