2014-09-24 7 views
5

Próbuję zwrócić obiekt SqlXml z metody, która inicjuje go przy użyciu metody lokalnego strumienia pamięci. To znaczy.Powracający SqlXml zainicjalizowany ze strumieniem pamięci

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

Teraz metoda, która wywołuje tę funkcję i próbuje uzyskać dostęp do jej pól, kończy się niepowodzeniem z object disposed exception.

Rzuciłem okiem na SqlXml.cs i zobaczyłem, że jest to po prostu odniesienie do strumienia, który opisuje zachowanie.

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

Naprawdę chciałbym uniknąć sytuacji, w której osoba dzwoniąca musi przejść strumień i być odpowiedzialnym za jego całe życie. Czy istnieje inny sposób na pełne zainicjowanie obiektu SqlXml i bezpieczne pozbycie się strumienia pamięci?

edit:

Możliwym rozwiązaniem jest mieć zmienną SQLXML temp, a następnie użyć go do zainicjowania obiektu powrotu poprzez tworzenie konstruktora czytnika:

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

Ale to nadal wygląda trochę przylegający do mnie.

+0

Jeśli dzwoniący żąda strumienia, powinien być odpowiedzialny za jego usunięcie. Kod generowania strumienia nie powinien być odpowiedzialny za jego usunięcie, ponieważ nie może on stwierdzić, kiedy strumień nie jest już potrzebny. Być może możesz stworzyć fabrykę lub użyć kontenera IOC do kontrolowania tworzenia, a następnie utylizacji strumienia. –

+0

Tak, ale strumień jest używany wewnętrznie do serializacji. Dzwoniący nie powinien się tym przejmować wewnętrznie (w tym przypadku za pośrednictwem strumienia). – Klark

+0

To prawda. Cóż, gdy zaczniesz zajmować się niezarządzanymi zasobami, w zarządzanym świecie pamięci dzieje się trochę mniej proste. Być może możesz wziąć kilka pomysłów z tej odpowiedzi na omawianie IDisposable i kto jest odpowiedzialny za usuwanie IDisposable implementors, które są przekazywane wokół: http://stackoverflow.com/a/7944828/9732 –

Odpowiedz

0

Instrukcja using wywoła utylizację strumienia po wyjściu bloku. Wyjmij MemoryStream z używanego bloku i nie wyrzuci go przed powrotem.

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); 
    } 
} 
Powiązane problemy