2014-09-24 3 views
5

Sto tentando di restituire un oggetto SqlXml da un metodo che lo inizializza utilizzando un metodo di memoria locale. CioèRitorno di SqlXml inizializzato con flusso di memoria

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); 
      } 
     } 

Ora il metodo che lo chiama e cerca di accedere ai suoi campi non riesce con un object disposed exception.

Ho dato una rapida occhiata a SqlXml.cs e ho visto che è solo mantenendo un riferimento al flusso che descrive il comportamento.

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; 
      } 

Vorrei davvero evitare che il chiamante debba passare il flusso ed essere responsabile della sua durata. C'è un altro modo per inizializzare completamente l'oggetto SqlXml e smaltire in modo sicuro il flusso di memoria?

edit:

Una possibile soluzione è quella di avere una variabile SqlXml temp e quindi utilizzarlo per inizializzare l'oggetto di ritorno via creare costruttore lettore:

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()); 
      } 
     } 

Ma questo sembra ancora un po 'goffo per me.

+0

Se un chiamante richiede un flusso, dovrebbe essere responsabile dello smaltimento. Il codice di generazione dello stream non dovrebbe essere responsabile per lo smaltimento in quanto non può sapere quando lo streaming non è più necessario. Forse potresti creare una fabbrica o usare un container IOC per controllare la creazione e quindi smaltire lo stream. –

+0

Sì, ma lo streaming è utilizzato internamente per la serializzazione. Il chiamante non dovrebbe preoccuparsi del modo in cui il metodo costruisce l'xml internamente (in questo caso tramite lo stream). – Klark

+0

Questo è vero. Bene, una volta che inizi a occuparti di risorse non gestite, le cose diventano un po 'meno semplici nel mondo della memoria gestita. Forse puoi prendere alcune idee da questa risposta discutendo di IDisposable e chi è responsabile per lo smaltimento di implementatori IDisposable che vengono passati in giro: http://stackoverflow.com/a/7944828/9732 –

risposta

0

L'istruzione using chiamerà dispose sullo streaming quando il blocco verrà chiuso. Porta il MemoryStream fuori dal blocco using e non lo eliminerà prima del ritorno.

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); 
    } 
} 
Problemi correlati