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:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
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 einesusing
-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 undN:
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. |
Ähnliche Regeln
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