Why a BinaryWriter closes the outer Stream on disposal, and how to prevent that? (.NET C#)
Asked Answered
U

4

30

I have one method that receives a Stream to write on it using a BinaryWriter. But when I dispose this BinaryWriter it also closes the stream. Can I leave it undisposed so I can leave my stream open?

Uncalledfor answered 5/7, 2009 at 20:55 Comment(0)
S
9

Just do not call Dispose, use Flush instead, its safe.

Steeple answered 5/7, 2009 at 21:3 Comment(8)
Yeah, I checked that on Reflector and it's true.Uncalledfor
It's safe today. Are you going to use Reflector on ever release of .NET to make sure it continues to be safe? This is not a solution. -1.Stigmatic
It will be always safe. Just because of writer semantics. Just think why it has dispose for now (hint look at examples on msdn). Also note that this is not the only place in .NET that incorrectly use IDisposable, for example well know Dispose problem with WCF channels.Steeple
I can say more, @Marc Gravell will fail the same way if Microsoft will change semantics of the Dispose in BinnaryWriter.Steeple
It has a dispose because it is assumed that it now owns the stream's lifetime. But if we don't want that, then I'd argue the correct thing to do is to separate the two - not hack how we use the writer. The writer is disposable; we should dispose it. In short, I disagree.Communize
It has dispose just because ONE of the usage scenarious assumes that it can own stream's lifetime. The fact that object is disposable is not something that requires to call dispose. Sometimes it just syntax helper. In the case of BinnaryWriter this is the case. (BTW BinnaryWriter is Serializable, lets make serialize it?, how so, how serialize writer?) Regarding hack, I am fail to see one.Steeple
"The fact that object is disposable is not something that requires to call dispose" - there we again disagree. IDisposable is a contract; unless you have a very good reason, you should dispose it when done. Anything else breaks encapsulation. You shouldn't know or care what it needs disposable for... it is disposable: dispose it. Replied to your other comment (on my post), too.Communize
Fortunately, BinaryWriter does not call Dispose in Finalize like FileStream does. This behavior implies that BinaryWriter.Dispose is optional.Presidium
A
59

As of .NET 4.5, the BinaryWriter class has a new constructor that takes a boolean parameter to indicate whether to leave the stream open or not.

Ref: http://msdn.microsoft.com/en-us/library/gg712841.aspx

public BinaryWriter(
    Stream output,
    Encoding encoding,
    bool leaveOpen
)
Adenectomy answered 21/8, 2012 at 17:24 Comment(1)
@JaderDias I know this is forever ago, but you should consider marking this as the answer.Effluvium
C
21

In the case of BinaryWriter, that isn't a direct option (although some stream wrappers do allow you to control this, for example GZipStream etc).

Jon has a NonClosingStreamWrapper in MiscUtil which should work: you wrap your stream in the non-closing wrapper, and give the wrapper to BinaryWriter. This essentially passes through everything except Close() and Dispose().

Communize answered 5/7, 2009 at 20:57 Comment(6)
Dont you think that there is a bit of hack? You suggest to change behavior(and assumtions) of the BinnaryWriter by fooling it with wrapper?Steeple
No, that changes nothing at all related with BinaryWriter; it writes values to a stream and tells the stream when it is finished. Care to expand on what you have in mind? It is certainly a lot less hacky than not disposing something that is IDisposable on the grounds that you peeked at the implementation and decided to overrule it...Communize
this changes expected behaviour of the binnary writer. because of expected behaviour of close and dispose operations, binnarywriter does not bother to flash. By filtering close and dispose functions you simply introduce bug that in cirtan circumstances hard to find.Steeple
When a BinaryWriter closes, it flushes itself and tells the stream to close; with the wrapper, it would still flush itself. The difference it that the stream doesn't close.Communize
Why does the NonClosingStreamWrapper throw an InvalidOperationException instead of an ObjectDisposedException after it is closed?Michelmichelangelo
@Michelmichelangelo feel free to edit it locally; I didn't write it :pCommunize
S
9

Just do not call Dispose, use Flush instead, its safe.

Steeple answered 5/7, 2009 at 21:3 Comment(8)
Yeah, I checked that on Reflector and it's true.Uncalledfor
It's safe today. Are you going to use Reflector on ever release of .NET to make sure it continues to be safe? This is not a solution. -1.Stigmatic
It will be always safe. Just because of writer semantics. Just think why it has dispose for now (hint look at examples on msdn). Also note that this is not the only place in .NET that incorrectly use IDisposable, for example well know Dispose problem with WCF channels.Steeple
I can say more, @Marc Gravell will fail the same way if Microsoft will change semantics of the Dispose in BinnaryWriter.Steeple
It has a dispose because it is assumed that it now owns the stream's lifetime. But if we don't want that, then I'd argue the correct thing to do is to separate the two - not hack how we use the writer. The writer is disposable; we should dispose it. In short, I disagree.Communize
It has dispose just because ONE of the usage scenarious assumes that it can own stream's lifetime. The fact that object is disposable is not something that requires to call dispose. Sometimes it just syntax helper. In the case of BinnaryWriter this is the case. (BTW BinnaryWriter is Serializable, lets make serialize it?, how so, how serialize writer?) Regarding hack, I am fail to see one.Steeple
"The fact that object is disposable is not something that requires to call dispose" - there we again disagree. IDisposable is a contract; unless you have a very good reason, you should dispose it when done. Anything else breaks encapsulation. You shouldn't know or care what it needs disposable for... it is disposable: dispose it. Replied to your other comment (on my post), too.Communize
Fortunately, BinaryWriter does not call Dispose in Finalize like FileStream does. This behavior implies that BinaryWriter.Dispose is optional.Presidium
L
9

The protected BinaryWriter.Dispose(bool) method is virtual, and all it does is closes the stream (you can check that it is true in Reflector). -This method is called by the Dispose() method.

You can simply inherit a class from the BinaryWriter and override the Dispose(bool) method to do nothing, or something else alltogether.

Loden answered 5/7, 2009 at 21:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.