Using XmlTextWriter without closing the base stream

M

Marc Gravell

I want to write a method that will accept a stream as a parameter, and which
will write xml to the stream (based in reality on database results) using
the XmlTextWriter class. However, this insists on closing my stream, and I
can't convince it not to.

A much-simplified example is below; basically, as soon as the writer is
disposed (marked **** below) the base stream gets closed - which is a pain
if I was still using it ;-p

The base XmlWriter class has a read-only Settings property which in turn has
a CloseOutput property; this would be fine, except Settings is null in the
following, so I can't get to an XmlSettings object to toggle this...

Is there any way to write to such a stream without it getting closed?

Thanks in advance,

Marc


using System;
using System.IO;
using System.Xml;
namespace ConsoleApplication1 {
public static class Program {
public static void Main() {
using (MemoryStream stream = new MemoryStream()) {
WriteXml(stream);
TestStream(stream); // fails - stream now closed on exit of
method
}
}
private static void TestStream(System.IO.Stream stream) {
Console.WriteLine(new string('=', 20));
try {
long position = stream.Position;
stream.Position = 0;
XmlDocument doc = new XmlDocument();
doc.Load(stream);
stream.Position = position;
Console.WriteLine(doc.OuterXml);
} catch (Exception e) {
Console.WriteLine(e); // absorb exception
}
}
public static void WriteXml(Stream stream) {
using (XmlTextWriter writer = new XmlTextWriter(stream, null)) {
writer.Formatting = Formatting.None;
writer.Namespaces = false;
writer.WriteStartElement("Xml");
writer.WriteStartElement("Element");
writer.WriteAttributeString("Attrib1", "Value1");
writer.WriteAttributeString("Attrib2", "Value2");
writer.WriteEndElement();
writer.WriteEndElement();
writer.Flush();
TestStream(writer.BaseStream); // works; stream still open
} // **** closes base stream
}
}
}
 
M

Marc Gravell

Thanks for replying; actually, I found that you can do this if you use one
of the overloads to XmlWriter.Create (which accepts the stream and a
settings object).

Marc
 
N

Nick Hounsome

If you don't want things disposed then don't dispose of them - remove the
"using" statement from WriteXml.

It is poor design for a method to dispose of a resource that it didn't
acquire [except of course in the case where its job is explicitly defined to
be disposing of the resource].

Also,depending on your design, you should only dispose of either the base
stream or the wrapper - you are effectively trying to do both.

You do not need to explicitly dispose of an XmlTextWriter anywhere unless
you have dispensed with the base stream - garbage collection will handle it
perfectly well.

Finally a MemoryStream is the one type of Stream that does not need to be
disposed AT ALL because it is just managed memory although it is good style
to treat it like any other stream.
 
M

Marc Gravell

I know what you are saying, and I am glad that I have found a resolution -
however, I'm not quite sure that I agree with all of your points:

Forgetting about streams and writers; if I have an object that is a:
disposable and b: I feel ownership for (in particular if I explicitely
created it), then my instinct tells me that I should dispose of that object.
Due to encapsulation, it isn't necessarily my business to know *exactly*
what is going on under the hood, for instance it could be using a windows
handle, a file, a database resource etc - not my problem.

So:

If I create a class (that happens to be called a stream), should I dispose
it when I am done? I think I should.
If I create a class (that happens to be called a writer, and which uses a
stream), should I still dispose it when I am done? I think I should.
Likewise with the memory stream; technically we know it doesn't need to be,
but that knowledge breaks the black-box rule of encapsulation.

For all I know, the implementation of either the stream or writer
(separately) could involve 17 other disposable / unmanaged objects (in
addition to my stream in the case of the writer), and I would like them to
be cleaned up properly and ASAP; I just don't want it to (necessarily)
dispose of an object that I am still using it just because it knows where it
is.

The main exceptions I can think of to scoped disposal are where I want one
to live longer than its natural scope (i.e. as a return value), but in my
example both entities were tightly scoped in a nested manner. It seems
logical to me to dispose of both of them in turn. Saying "ahh, but its a
stream, so only dispose of it at one level" pollutes things quite a bit to
my mind.

Anyway - I'm happy to disagree, and I'm happy (for this nested usage) to use
a ctor that lets me do this. And I really can see what you are saying about
other uses - I'm just saying that it should be up to me (which, it turns
out, it is). Other examples of more-conveniently handled wrappers are the
compression classes - these take a boolean on an overloaded ctor to let you
tell it "do you want me to close your stream for you?" - and yes, most of
the time you might.

Cheers for the input,

Marc
 
J

Jon Skeet [C# MVP]

Marc Gravell wrote:

Forgetting about streams and writers; if I have an object that is a:
disposable and b: I feel ownership for (in particular if I explicitely
created it), then my instinct tells me that I should dispose of that object.
Due to encapsulation, it isn't necessarily my business to know *exactly*
what is going on under the hood, for instance it could be using a windows
handle, a file, a database resource etc - not my problem.

<snip>

I entirely agree. I have my own class which might help you with further
such issues:
NonClosingStreamWrapper, which is in my miscellaneous utility library
(although I note I don't mention it on the front page,
unfortunately...)

http://www.pobox.com/~skeet/csharp/miscutil/

Jon
 
M

Marc Gravell

A handy wrapper class; next time I have such an issue (and can't find a
suitable ctor, which is probably the best solution in that it keeps things
simple) I may well make use of this.

Cheers,

Marc
 
N

Nick Hounsome

Marc Gravell said:
I know what you are saying, and I am glad that I have found a resolution -
however, I'm not quite sure that I agree with all of your points:

Forgetting about streams and writers; if I have an object that is a:
disposable and b: I feel ownership for (in particular if I explicitely
created it), then my instinct tells me that I should dispose of that
object. Due to encapsulation, it isn't necessarily my business to know
*exactly* what is going on under the hood, for instance it could be using
a windows handle, a file, a database resource etc - not my problem.

So:

If I create a class (that happens to be called a stream), should I dispose
it when I am done? I think I should.
Agreed.

If I create a class (that happens to be called a writer, and which uses a
stream), should I still dispose it when I am done? I think I should.

No - because it uses the stream - it doesn't own it and it doesn't own
anything that needs disposing so it shouldn't be disposed.
Likewise with the memory stream; technically we know it doesn't need to
be, but that knowledge breaks the black-box rule of encapsulation.

That's why I said that good practice would be to dispose of it anyway.
For all I know, the implementation of either the stream or writer
(separately) could involve 17 other disposable / unmanaged objects (in
addition to my stream in the case of the writer), and I would like them to

I think it is quite clear the the writer only implements IDisposable so as
to close the stream.

For the reason that you give it would be very bad practice to have a class
own one resource but just use another.
be cleaned up properly and ASAP; I just don't want it to (necessarily)
dispose of an object that I am still using it just because it knows where
it is.

The main exceptions I can think of to scoped disposal are where I want one
to live longer than its natural scope (i.e. as a return value), but in my
example both entities were tightly scoped in a nested manner. It seems
logical to me to dispose of both of them in turn. Saying "ahh, but its a
stream, so only dispose of it at one level" pollutes things quite a bit to
my mind.

I agree that you can make a case for XmlTextWriter not implementing
IDisposable but I suppose that it is just too useful in the common case
where the stream is a file.
Anyway - I'm happy to disagree, and I'm happy (for this nested usage) to
use a ctor that lets me do this. And I really can see what you are saying
about other uses - I'm just saying that it should be up to me (which, it
turns out, it is). Other examples of more-conveniently handled wrappers
are the compression classes - these take a boolean on an overloaded ctor
to let you tell it "do you want me to close your stream for you?" - and
yes, most of the time you might.

I think that I'd probably agree though that that is the best solution
although a bit ugly. It is just one of the many unfortunate examples of
different practices used in different parts of the framework.
 
J

Jon Skeet [C# MVP]

Nick Hounsome said:
No - because it uses the stream - it doesn't own it and it doesn't own
anything that needs disposing so it shouldn't be disposed.

How do you know that it (the created instance) doesn't have *other*
things which need to be disposed though?
That's why I said that good practice would be to dispose of it anyway.


I think it is quite clear the the writer only implements IDisposable so as
to close the stream.

If we're going to go by what's "quite clear" then I don't see that it's
good practice to dispose of a MemoryStream, as it's "quite clear" that
that doesn't have any other resources. Going by intuition is a bad idea
in this kind of thing, IMO.
For the reason that you give it would be very bad practice to have a class
own one resource but just use another.

But that could certainly be the situation in some cases. In those
cases. In those cases, I believe the API should allow you to specify
which resources are effectively owned by the class you're passing them
to, and which resources are owned by the caller.

I think that I'd probably agree though that that is the best solution
although a bit ugly. It is just one of the many unfortunate examples of
different practices used in different parts of the framework.

I don't see it as ugly particularly - it's just a matter of telling the
API what it owns and what it doesn't own. In some cases it will be
useful for the new object to own the resource, in some cases not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top