Udostępnij za pośrednictwem


CA2000: Zbywać obiektów przed utratą zakresu

TypeName

DisposeObjectsBeforeLosingScope

CheckId

CA2000

Kategoria

Microsoft.Reliability

Zmiana kluczowa

Niekluczowa

Przyczyna

Lokalny obiekt typu IDisposable został utworzony, ale obiektu nie jest usuwany, zanim wszystkie odwołania do obiektu są poza zakresem.

Opis reguły

Jeśli obiekt usuwalny nie jest jawnie usuwany zanim wszystkie odwołania do niego są poza zakresem, obiekt zostanie usunięty w nieokreślonym czasie, gdy moduł usuwający elementy bezużyteczne pamięci uruchomi finalizator obiektu.Ponieważ może wystąpić nieoczekiwane zdarzenie, które uniemożliwi uruchomienie finalizatora, obiekt należy jawnie usunąć.

Jak naprawić naruszenia

Aby naprawić naruszenie tej zasady, należy wywołać dla obiektu Dispose zanim wszystkie odwołania do tego obiektu znajdą się poza zakresem.

Należy zauważyć, że można użyć instrukcji using (Using w Visual Basic) aby otoczyć obiekty implementujące IDisposable.Obiekty, które są pakowane w ten sposób automatycznie zostaną usunięte po zamknięciu bloku using.

Poniżej opisano sytuacje, w których za instrukcja using nie wystarcza do ochrony obiektów IDisposable i może spowodować wystąpienie CA2000.

  • Zwracanie obiektu usuwalnego wymaga, aby obiekt został skonstruowany w bloku try/finally poza blokiem using.

  • Inicjowanie elementów członkowskich usuwalnego obiektu nie powinno być dokonywane w konstruktorze przy użyciu instrukcji using.

  • Zagnieżdżone konstruktory, które są chronione tylko przez jeden blok obsługi wyjątków.Na przykład:

    using (StreamReader sr = new StreamReader(new FileStream("C:\myfile.txt", FileMode.Create)))
    { ... }
    

    powoduje CA2000, ponieważ błąd podczas tworzenia obiektu StreamReader może spowodować, że obiekt FileStream nigdy nie zostanie zamknięty.

  • Obiekty dynamiczne powinny używać obiektu cienia do zaimplementowania wzorca usuwanie obiektów IDisposable.

Kiedy pomijać ostrzeżenia

Nie pomijaj ostrzeżeń od tej reguły, chyba że wywołujesz ją na obiekcie, który wywołuje metodę Dispose, takim jak Close.

Powiązane reguły

CA2213: Winny być usuwane jednorazowe pól

CA2202: Nie usuwaj obiekty wiele razy

Przykład

Jeśli implementujesz metodę, która zwraca obiekt usuwalny, użyj bloku try/finally bez bloku catch aby upewnić się, że obiekt jest usuwany.Poprzez użycie bloku try/finally, zezwala się na zgłaszanie wyjątków w punkcie usterki i zapewnia się, że obiekt jest usuwany.

W metodzie OpenPort1 wywołanie otwarcia obiektu ISerializable portu SerialPort lub wywołanie SomeMethod może się nie powieść.Ostrzeżenie CA2000 jest wywoływane dla tej implementacji.

W metodzie OpenPort2 dwa obiekty portu SerialPort są deklarowane i ustawiane na wartość null:

  • tempPort, służący do sprawdzenia, że operacje metody powiodły się.

  • port, który jest używany dla wartości zwracanej metody.

tempPort jest tworzony i otwierany w bloku try oraz wszelka inna wymagana praca jest wykonywana w tym samym bloku try.Na koniec bloku try otwarty port jest przypisywany do obiektu port, który zostanie zwrócony i obiekt tempPort jest ustawiany na wartość null.

Blok finally sprawdza wartość tempPort.Jeśli nie jest równa null, operacja w metodzie nie powidła się i tempPort zostaje zamknięty, aby upewnić się, że wszystkie zasoby zostaną zwolnione.Obiekt zwrócony portu będzie zawierać otwarty obiekt portu SerialPort jeśli operacje metody powiodą się lub przyjmie wartość null, jeśli operacja nie powiedzie się.

Public Function OpenPort1(ByVal PortName As String) As SerialPort

   Dim port As New SerialPort(PortName)
   port.Open()    'CA2000 fires because this might throw
   SomeMethod()   'Other method operations can fail
   Return port

End Function


Public Function OpenPort2(ByVal PortName As String) As SerialPort

   Dim tempPort As SerialPort = Nothing
   Dim port As SerialPort = Nothing

   Try
      tempPort = New SerialPort(PortName)
      tempPort.Open()
      SomeMethod()
      'Add any other methods above this line
      port = tempPort
      tempPort = Nothing

   Finally
      If Not tempPort Is Nothing Then
         tempPort.Close()
      End If


   End Try

   Return port

End Function

Public Function CreateReader1(ByVal x As Integer) As StreamReader
   Dim local As New StreamReader("C:\Temp.txt")
   x += 1
   Return local
End Function


Public Function CreateReader2(ByVal x As Integer) As StreamReader
   Dim local As StreamReader = Nothing
   Dim localTemp As StreamReader = Nothing
   Try
      localTemp = New StreamReader("C:\Temp.txt")
      x += 1
      local = localTemp
      localTemp = Nothing
      Finally
         If (Not (localTemp Is Nothing)) Then
            localTemp.Dispose()
         End If
   End Try
   Return local
End Function

public SerialPort OpenPort1(string portName)
{
   SerialPort port = new SerialPort(portName);
   port.Open();  //CA2000 fires because this might throw
   SomeMethod(); //Other method operations can fail
   return port;
}

public SerialPort OpenPort2(string portName)
{
   SerialPort tempPort = null;
   SerialPort port = null;
   try
   {
      tempPort = new SerialPort(portName);
      tempPort.Open();
      SomeMethod();
      //Add any other methods above this line
      port = tempPort;
      tempPort = null;

   }
   finally
   {
      if (tempPort != null)
      {
         tempPort.Close();
      }
   }
   return port;
}

Domyślnie kompilator Visual Basic ma sprawdza przepełnienie dla wszystkich operatorów arytmetycznych.Dlatego każda operacja arytmetycznej Visual Basic może zgłosić OverflowException.Mogłoby to doprowadzić do nieoczekiwanego naruszenia zasad, takich jak CA2000.Na przykład poniższa funkcja CreateReader1 spowoduje naruszenie CA2000 ponieważ kompilator języka Visual Basic emituje instrukcję sprawdzania przepełnienia dla dodawania, która może zgłosić wyjątek, który mogłyby spowodować, że obiekt StreamReader nie zostałby usunięty.

Aby rozwiązać ten problem, można wyłączyć emisję kontroli przepełnienia przez kompilator Visual Basic w projekcie lub można zmodyfikować kod tak jak w funkcji CreateReader2.

Aby wyłączyć emisję sprawdzania przepełnienia, kliknij prawym przyciskiem myszy nazwę projektu w oknie Eksploratora rozwiązania, a następnie kliknij przycisk Właściwości.Kliknij Skompiluj, kliknij Zaawansowane opcje kompilacji, a następnie sprawdź Usuń sprawdzenia przepełnienia liczb całkowitych.

Zobacz też

Informacje

IDisposable

Implementing Finalize and Dispose