5

I am trying to return an SqlXml object from a method which initializes it using a method local memory stream. I.e.

using (Stream memoryStream = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(memoryStream, new XmlWriterSettings { OmitXmlDeclaration = true }))
            {
                serializer.Serialize(writer, myList.ToArray(), ns);
                return new SqlXml(memoryStream);
            }
        }

Now the method that calls it and tries to access it's fields fails with an object disposed exception.

I gave a quick glance at SqlXml.cs and saw it is just keeping an reference to the stream which describes the behaviour.

public SqlXml(Stream value) {
            // whoever pass in the stream is responsible for closing it
            // similar to SqlBytes implementation
            if (value == null) {
                SetNull();
            }
            else  {
                firstCreateReader = true;
                m_fNotNull = true;
                m_stream = value;
            }

I would really like to avoid caller having to pass the stream and being responsible for it's lifetime. Is there any other way to fully initializing the SqlXml object and safely disposing the memory stream?

edit:

One possible solution is to have a temp SqlXml variable and then use it to initialize return object via create reader constructor:

using (Stream memoryStream = new MemoryStream())
        {
            using (XmlWriter writer = XmlWriter.Create(memoryStream, new XmlWriterSettings { OmitXmlDeclaration = true }))
            {
                serializer.Serialize(writer, myList.ToArray(), ns);
                SqlXml s = new SqlXml(memoryStream);
                return new SqlXml(s.CreateReader());
            }
        }

But this still looks a bit clunky to me.

Klark
  • 8,162
  • 3
  • 37
  • 61
  • If a caller is requesting a stream they should be responsible for disposing of it. The stream generation code should not be responsible for disposing of it since it cannot know when the stream is no longer needed. Perhaps you could create a factory or use an IOC container to control the creation and then disposing of the stream. – Jason Down Sep 24 '14 at 17:38
  • Yeah, but stream is used internally for serialization. Caller shouldn't really care about how the method constructs the xml internally (in this case being via the stream). – Klark Sep 24 '14 at 17:41
  • That is true. Well once you start dealing with unmanaged resources things get a little less straightforward in the managed memory world. Perhaps you can take some ideas from this answer discussing IDisposable and who is responsible for disposing IDisposable implementors that are passed around: http://stackoverflow.com/a/7944828/9732 – Jason Down Sep 24 '14 at 17:49

1 Answers1

0

The using statement will call dispose on the stream when the block exits. Take the MemoryStream out of the using-block and it will not dispose before return.

class Program
{
    static void Main(string[] args)
    {
        var s = GetData();
        var r = s.CreateReader();
        while (r.Read())
        {
            if (r.NodeType == XmlNodeType.Element)
            {
                System.Console.WriteLine(r.Name);
            }
        }
        r.Close();
    }

    private static SqlXml GetData()
    {
        var mem = new MemoryStream();
        //TODO: Deserialize or query data.
        return new SqlXml(mem);
    }
}
Keith
  • 100
  • 1