CA2000: Objekte verwerfen, bevor Bereich verloren geht.

Eigenschaft Wert
Regel-ID CA2000
Titel Objekte verwerfen, bevor Bereich verloren geht.
Kategorie Zuverlässigkeit
Fix führt oder führt nicht zur Unterbrechung Nicht unterbrechend
Standardmäßig in .NET 8 aktiviert Nein

Ursache

Es wird ein lokales Objekt eines IDisposable-Typs erstellt. Das Objekt wird jedoch erst verworfen, nachdem sich alle Verweise auf das Objekt außerhalb des gültigen Bereichs befinden.

Standardmäßig analysiert diese Regel die gesamte Codebasis, aber dieses Verhalten ist konfigurierbar.

Regelbeschreibung

Wenn ein verwerfbares Objekt nicht explizit verworfen wird, bevor alle Verweise darauf außerhalb des gültigen Bereichs liegen, wird das Objekt zu einer unbestimmten Zeit verworfen, wenn der Garbage Collector den Finalizer des Objekts ausführt. Da möglicherweise ein Ausnahmeereignis auftritt, durch das die Ausführung des Finalizers des Objekts verhindert wird, muss das Objekt stattdessen explizit verworfen werden.

Spezialfälle

Regel CA2000 wird nicht für lokale Objekte der folgenden Typen ausgelöst, auch wenn das Objekt nicht verworfen wird:

Wenn Sie ein Objekt eines dieser Typen an einen Konstruktor übergeben und dann einem Feld zuweisen, wird ein Übertragung der Verwerfungsverantwortung an den neu erstellten Typ angegeben. Das heißt, der neu konstruierte Typ ist nun für das Verwerfen des Objekts verantwortlich. Wenn Ihr Code ein Objekt eines dieser Typen an einen Konstruktor übergibt, tritt kein Verstoß gegen die Regel CA2000 auf, auch wenn das Objekt nicht verworfen wird, bevor alle Verweise darauf außerhalb des gültigen Bereichs liegen.

Behandeln von Verstößen

Um einen Verstoß gegen diese Regel zu beheben, rufen Sie Dispose für das Objekt auf, bevor sich alle Verweise darauf außerhalb des gültigen Bereichs befinden.

Sie können die using Anweisung (Using in Visual Basic) verwenden, um Objekte zu umschließen, die IDisposable implementieren. Auf diese Weise umschlossene Objekte werden zum Abschluss des using-Blocks automatisch verworfen. Die folgenden Situationen sollten oder können jedoch nicht mit einer using-Anweisung gehandhabt werden:

  • Um ein verwerfbares Objekt zurückzugeben, muss das Objekt in einem try/finally-Block außerhalb eines using-Blocks erstellt werden.

  • Initialisieren Sie Member eines verwerfbaren Objekts nicht im Konstruktor einer using-Anweisung.

  • Wenn Konstruktoren, die nur durch einen Ausnahmehandler geschützt sind, im -Erwerbsteil einer using-Anweisung verschachtelt werden, kann ein Fehler im äußeren Konstruktor dazu führen, dass das Objekt, das vom verschachtelten Konstruktor erstellt wurde, nie geschlossen wird. Im folgenden Beispiel kann ein Fehler im StreamReader-Konstruktor dazu führen, dass das FileStream-Objekt nie geschlossen wird. CA2000 kennzeichnet in diesem Fall einen Verstoß gegen die Regel.

    using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create)))
    { ... }
    
  • Dynamische Objekte sollten ein Schattenobjekt verwenden, um das Verwerfungsmuster von IDisposable-Objekten zu implementieren.

Wann sollten Warnungen unterdrückt werden?

Unterdrücken Sie keine Warnung dieser Regel, es sei denn:

  • Sie haben eine Methode für das Objekt aufgerufen, das Dispose aufruft, beispielsweise Close.
  • Die Methode, welche die Warnung ausgelöst hat, gibt ein IDisposable-Objekt zurück, das Ihr Objekt umschließt.
  • Die Zuweisungsmethode hat keine Verwerfungsverantwortung. Das heißt, die Verantwortung für das Verwerfen des Objekts wird an ein anderes Objekt oder einen Wrapper übertragen, das in der Methode erstellt und an den Aufrufer zurückgegeben wird.

Unterdrücken einer Warnung

Um nur eine einzelne Verletzung zu unterdrücken, fügen Sie der Quelldatei Präprozessoranweisungen hinzu, um die Regel zu deaktivieren und dann wieder zu aktivieren.

#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000

Um die Regel für eine Datei, einen Ordner oder ein Projekt zu deaktivieren, legen Sie den Schweregrad in der Konfigurationsdatei auf none fest.

[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none

Weitere Informationen finden Sie unter Vorgehensweise: Unterdrücken von Codeanalyse-Warnungen.

Konfigurieren des zu analysierenden Codes

Mithilfe der folgenden Optionen können Sie konfigurieren, für welche Teile Ihrer Codebasis diese Regel ausgeführt werden soll.

Sie können diese Optionen nur für diese Regel, für alle zutreffenden Regeln oder für alle zutreffenden Regeln in dieser Kategorie (Zuverlässigkeit) konfigurieren. Weitere Informationen finden Sie unter Konfigurationsoptionen für die Codequalitätsregel.

Ausschließen bestimmter Symbole

Sie können bestimmte Symbole, z. B. Typen und Methoden, von der Analyse ausschließen. Sie können beispielsweise festlegen, dass die Regel nicht für Code innerhalb von Typen namens MyType ausgeführt werden soll, indem Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzufügen:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Zulässige Formate für Symbolnamen im Optionswert (durch | getrennt):

  • Nur Symbolname (schließt alle Symbole mit dem Namen ein, unabhängig vom enthaltenden Typ oder Namespace)
  • Vollqualifizierte Namen im Format der Dokumentations-ID des Symbols Jeder Symbolname erfordert ein Symbolartpräfix, z. B. M: für Methoden, T: für Typen und N: für Namespaces.
  • .ctor für Konstruktoren und .cctor für statische Konstruktoren

Beispiele:

Optionswert Zusammenfassung
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType Trifft auf alle Symbole namens MyType zu
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 Trifft auf alle Symbole namens MyType1 oder MyType2 zu
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Trifft speziell auf die Methode MyMethod mit der angegebenen vollqualifizierten Signatur zu
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Trifft speziell auf die Methoden MyMethod1 und MyMethod2 mit den jeweiligen vollqualifizierten Signaturen zu

Ausschließen bestimmter Typen und von diesen abgeleiteten Typen

Sie können bestimmte Typen und von diesen abgeleitete Typen aus der Analyse ausschließen. Wenn Sie z. B. festlegen möchten, dass die Regel nicht für Methoden innerhalb von MyType-Typen und von diesen abgeleiteten Typen ausgeführt werden soll, fügen Sie einer EDITORCONFIG-Datei in Ihrem Projekt das folgende Schlüssel-Wert-Paar hinzu:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Zulässige Formate für Symbolnamen im Optionswert (durch | getrennt):

  • Nur Typname (schließt alle Typen mit dem Namen ein, unabhängig vom enthaltenden Typ oder Namespace)
  • Vollqualifizierte Namen im Dokumentations-ID-Format des Symbols mit einem optionalen Präfix T:

Beispiele:

Optionswert Zusammenfassung
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Stimmt mit allen MyType-Typen und allen von diesen abgeleiteten Typen überein.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 Stimmt mit allen MyType1- oder MyType2-Typen und allen von diesen abgeleiteten Typen überein.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Stimmt mit einem bestimmten MyType-Typ mit einem angegebenen vollqualifizierten Namen und allen von diesem abgeleiteten Typen überein.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Stimmt mit bestimmten MyType1- und MyType2-Typen mit den entsprechenden vollqualifizierten Namen und allen von diesen abgeleiteten Typen überein.

Beispiel 1

Wenn Sie eine Methode implementieren, die ein verwerfbares Objekt zurückgibt, verwenden Sie einen try/finally-Block ohne einen catch-Block, um sicherzustellen, dass das Objekt verworfen wird. Mit einem try/finally-Block lassen Sie Ausnahmen zu, die am Fehlerpunkt ausgelöst werden sollen, und stellen sicher, dass das Objekt verworfen wird.

In der OpenPort1-Methode kann der Aufruf zum Öffnen des SerialPorts des ISerializable-Objekts oder der Aufruf von SomeMethod fehlschlagen. Eine CA2000-Warnung wird für diese Implementierung ausgelöst.

In der OpenPort2-Methode werden zwei SerialPort-Objekte deklariert und auf NULL festgelegt:

  • tempPort zum Testen, ob die Methodenoperationen erfolgreich ausgeführt werden.

  • port für den Rückgabewert der Methode.

tempPort wird erstellt und in einem try-Block geöffnet. Alle anderen erforderlichen Arbeiten werden im gleichen try-Block ausgeführt. Am Ende des try-Blocks wird dem port-Objekt, das zurückgegeben wird, der geöffnete Port zugewiesen und das tempPort-Objekt wird auf null festgelegt.

Der finally-Block überprüft den Wert von tempPort. Wenn nicht NULL, ist eine Operation in der Methode fehlgeschlagen und tempPort wird geschlossen, um sicherzustellen, dass alle Ressourcen freigegeben werden. Das zurückgegebene Port-Objekt enthält das geöffnete SerialPort-Objekt, wenn die Operationen der Methode erfolgreich waren, oder es ist NULL, wenn eine Operation fehlschlug.

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

Beispiel 2

Standardmäßig überprüft der Visual Basic-Compiler auf Überläufe mit allen arithmetischen Operatoren. Daher kann jede arithmetische Visual Basic-Operation eine OverflowException auslösen. Dies kann zu unerwarteten Regelverletzungen führen, z. B. CA2000. Die folgende CreateReader1-Funktion erzeugt z. B. eine CA2000-Verletzung, da der Visual Basic-Compiler einen Befehl zur Überlaufprüfung für die Hinzufügung ausgibt, die eine Ausnahme auslösen könnte, durch die der StreamReader nicht verworfen werden würde.

Um dieses zu korrigieren, können Sie das Ausgeben von Überlaufprüfungen durch den Visual Basic-Compiler im Projekt deaktivieren, oder Sie können den Code entsprechend der folgenden CreateReader2-Funktion ändern.

Um das Ausgeben von Überlaufprüfungen zu deaktivieren, klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektnamen, und wählen Sie anschließend Eigenschaften aus. Wählen Sie Kompilieren>Erweiterte Kompilierungsoptionen aus, und aktivieren Sie dann Überprüfungen auf Ganzzahlüberlauf entfernen.

Imports System.IO

Class CA2000
    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
End Class

Siehe auch