2010-10-20 19 views
28

Kiedy biegnę analizy kodu na poniższym fragmencie kodu otrzymuję komunikat:„Obiekt można wyrzucać więcej niż jeden raz” błąd

Object „strumień” może być umieszczony więcej niż jeden raz w metodzie „upload.Page_Load (obiekt, EventArgs) ". Aby uniknąć generowania wyjątku System.ObjectDisposedException, nie należy wywoływać więcej niż jeden raz na obiekcie.

using(var stream = File.Open(newFilename, FileMode.CreateNew)) 
using(var reader = new BinaryReader(file.InputStream)) 
using(var writer = new BinaryWriter(stream)) 
{ 
    var chunk = new byte[ChunkSize]; 
    Int32 count; 
    while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
    { 
     writer.Write(chunk, 0, count); 
    } 
} 

Nie rozumiem, dlaczego może być wywołana dwa razy i jak to naprawić, aby wyeliminować błąd. Jakaś pomoc?

+1

dzień dzisiejszy VS2017 jest rzucanie CA2202 o każdy 'using' klauzuli. Ktoś musi działać razem. – ajeh

Odpowiedz

6

BinaryReader/BinaryWriter wyśle ​​dla ciebie strumień bazowy, gdy się go zbudzi. Nie musisz tego robić jawnie.

Aby to naprawić, możesz usunąć użycie wokół samego strumienia.

5

Twój pisarz odeśle twój strumień, zawsze.

13

Aby zilustrować, niech edytować kod

using(var stream = File.Open(newFilename, FileMode.CreateNew)) 
{ 
    using(var reader = new BinaryReader(file.InputStream)) 
    { 
     using(var writer = new BinaryWriter(stream)) 
     { 
      var chunk = new byte[ChunkSize]; 
      Int32 count; 
      while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
      { 
       writer.Write(chunk, 0, count); 
      } 
     } // here we dispose of writer, which disposes of stream 
    } // here we dispose of reader 
} // here we dispose a stream, which was already disposed of by writer 

Aby tego uniknąć, wystarczy utworzyć pisarza bezpośrednio

using(var reader = new BinaryReader(file.InputStream)) 
    { 
     using(var writer = new BinaryWriter(File.Open(newFilename, FileMode.CreateNew))) 
     { 
      var chunk = new byte[ChunkSize]; 
      Int32 count; 
      while((count = reader.Read(chunk, 0, ChunkSize)) > 0) 
      { 
       writer.Write(chunk, 0, count); 
      } 
     } // here we dispose of writer, which disposes of its inner stream 
    } // here we dispose of reader 

edit: należy wziąć pod uwagę to, co Eric Lippert mówi, że może rzeczywiście być momentem, w którym strumień zostanie zwolniony przez finalizatora, jeśli BinaryWriter zgłasza wyjątek. Zgodnie z kodeksem BinaryWriter, które mogą występować w trzech przypadkach

If (output Is Nothing) Then 
     Throw New ArgumentNullException("output") 
    End If 
    If (encoding Is Nothing) Then 
     Throw New ArgumentNullException("encoding") 
    End If 
    If Not output.CanWrite Then 
     Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable")) 
    End If 
  • jeśli nie określił wyjście, czyli jeśli strumień jest null. Nie powinno to stanowić problemu, ponieważ strumień zerowy oznacza brak zasobów do utylizacji :)
  • , jeśli nie określono kodowania. ponieważ nie używamy formularza konstruktora, w którym określono kodowanie, nie powinno tu być problemu (nie zaglądałem zbytnio w kodowanie contructor, ale może wrzucić niepoprawną stronę kodową)
    • jeśli nie t przekazać zapisywalny strumień. To powinno być złapany dość szybko w trakcie rozwoju ...

Zresztą dobry punkt, stąd edit :)

+2

Co teraz, jeśli nowy program BinaryWriter wyrzuci po otwarciu strumienia wyjściowego? Kto zamyka wtedy strumień? Nikt, dopóki finalizator nie uruchomi się. W praktyce tak się nie dzieje i praktycznie, nawet jeśli tak się stanie, najgorszą konsekwencją jest to, że plik pozostaje otwarty zbyt długo. Ale jeśli twoja logika * wymaga *, aby wszystkie zasoby były agresywnie oczyszczane, bez względu na to, jakie szalone wyjątki się zdarzają, wtedy ten kod jest niepoprawny. –

+0

@Eric: tak, ale ponieważ nie ma sposobu, aby sprawdzić, czy strumień plików jest już zamknięty, nie możemy tego łatwo wziąć pod uwagę. Gdybyśmy mieli obiekt zamknięty() jako wartość logiczną w strumieniu, moglibyśmy dodać zamykania logiki FILESTREAM do obsługi specjalnych przypadków, w których wystąpi wyjątek w Binary konstruktora Writer – samy

+0

Dokładniej, jeśli mogę użyć powyższy kod, a analiza kodu run pojawia się komunikat o błędzie: rozmowę System.IDisposable.Dispose na obiekcie 'File.Open (string.Concat (upload.BaseDir, newID CS $ <> 8__locals3.suffix) FileMode.CreateNew)' przed wszystkimi odniesieniami do jest poza zakresem. –

5

Prawidłowa realizacja Zużyty jest wyraźnie wymagane nie obchodzi mnie, czy to zostało nazwane więcej niż jeden raz na tym samym obiekcie. Podczas gdy wiele wywołań do Pozbywania się czasami wskazuje na problemy logiczne lub kod, który mógłby być lepiej napisany, jedynym sposobem, w jaki poprawiłbym pierwotnie opublikowany kod, byłoby przekonanie Microsoftu do dodania opcji do BinaryReadera i BinaryWriter nakazującej im, aby nie pozbyć się ich w strumieniu (a następnie użyj tej opcji). W przeciwnym razie kod wymagany do zamknięcia pliku, nawet jeśli jego autor lub konstruktor rzuci w jego konstruktor, byłby wystarczająco brzydki, że pozwoliłby na to, aby plik był usuwany więcej niż jeden raz.

10

Zmagałem się z tym problemem i uznałem przykład here za bardzo pomocny.wyślę kod do szybkiego widzenia:

using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate)) 
{ 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     // Use the writer object... 
    } 
} 

Wymień zewnętrzną za pomocą komunikatu z try/finally upewniając się zarówno zerowy strumień po użyciu go w StreamWriter I upewnij się, że nie jest null w w końcu przed pozbyciem się.

Stream stream = null; 
try 
{ 
    stream = new FileStream("file.txt", FileMode.OpenOrCreate); 
    using (StreamWriter writer = new StreamWriter(stream)) 
    { 
     stream = null; 
     // Use the writer object... 
    } 
} 
finally 
{ 
    if(stream != null) 
     stream.Dispose(); 
} 

Wykonanie tego wyczyściło moje błędy.

+0

I dziękuję za link MSDN. – Jedidja

Powiązane problemy