CA2000: Ta bort objekt innan du förlorar omfånget
Property | Värde |
---|---|
Regel-ID | CA2000 |
Title | Ta bort objekt innan du förlorar omfånget |
Kategori | Tillförlitlighet |
Korrigeringen är icke-bakåtkompatibel | Icke-icke-bryta |
Aktiverad som standard i .NET 9 | Nej |
Orsak
Ett lokalt objekt av en IDisposable typ skapas, men objektet tas inte bort innan alla referenser till objektet ligger utanför omfånget.
Som standard analyserar den här regeln hela kodbasen, men detta kan konfigureras.
Regelbeskrivning
Om ett disponibelt objekt inte uttryckligen tas bort innan alla referenser till det ligger utanför omfånget tas objektet bort vid en obestämd tidpunkt när skräpinsamlaren kör objektets slutversion. Eftersom en exceptionell händelse kan inträffa som förhindrar att slutföraren av objektet körs, bör objektet uttryckligen tas bort i stället.
Särskilda fall
Regel CA2000 utlöses inte för lokala objekt av följande typer även om objektet inte tas bort:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Att skicka ett objekt av någon av dessa typer till en konstruktor och sedan tilldela det till ett fält anger en överföring av ägarskap till den nyligen konstruerade typen. Det innebär att den nyligen konstruerade typen nu ansvarar för att ta bort objektet. Om koden skickar ett objekt av någon av dessa typer till en konstruktor sker ingen överträdelse av regeln CA2000 även om objektet inte tas bort innan alla referenser till det ligger utanför omfånget.
Så här åtgärdar du överträdelser
Om du vill åtgärda en överträdelse av den här regeln anropar Dispose du objektet innan alla referenser till den ligger utanför omfånget.
Du kan använda -instruktionen using
(Using
i Visual Basic) för att omsluta objekt som implementerar .IDisposable Objekt som omsluts på det här sättet tas bort automatiskt i slutet av using
blocket. Följande situationer bör dock inte eller kan inte hanteras med en using
instruktion:
Om du vill returnera ett disponibelt objekt måste objektet konstrueras i ett
try/finally
block utanför ettusing
block.Initiera inte medlemmar i ett disponibelt objekt i konstruktorn för en
using
-instruktion.När konstruktorer som endast skyddas av en undantagshanterare kapslas i förvärvsdelen av en
using
-instruktion kan ett fel i den yttre konstruktorn leda till att objektet som skapas av den kapslade konstruktorn aldrig stängs. I följande exempel kan ett fel i StreamReader konstruktorn leda till FileStream att objektet aldrig stängs. CA2000 flaggar ett brott mot regeln i det här fallet.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
Dynamiska objekt bör använda ett skuggobjekt för att implementera mönstret för bortskaffning av IDisposable objekt.
När du ska ignorera varningar
Utelämna inte en varning från den här regeln om inte:
- Du har anropat en metod för objektet som anropar
Dispose
, till exempel Close. - Metoden som aktiverade varningen returnerar ett IDisposable objekt som omsluter objektet.
- Allokeringsmetoden har inte ägarskap för bortskaffande. Det vill säga ansvaret för att ta bort objektet överförs till ett annat objekt eller omslutning som skapas i metoden och returneras till anroparen.
Ignorera en varning
Om du bara vill förhindra en enda överträdelse lägger du till förprocessordirektiv i källfilen för att inaktivera och aktiverar sedan regeln igen.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
Om du vill inaktivera regeln för en fil, mapp eller ett projekt anger du dess allvarlighetsgrad till none
i konfigurationsfilen.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
Mer information finns i Så här utelämnar du kodanalysvarningar.
Konfigurera kod för analys
Använd följande alternativ för att konfigurera vilka delar av kodbasen som regeln ska köras på.
Du kan konfigurera dessa alternativ för bara den här regeln, för alla regler som den gäller för eller för alla regler i den här kategorin (Tillförlitlighet) som den gäller för. Mer information finns i Konfigurationsalternativ för kodkvalitetsregel.
Exkludera specifika symboler
Du kan exkludera specifika symboler, till exempel typer och metoder, från analys. Om du till exempel vill ange att regeln inte ska köras på någon kod inom typer med namnet MyType
lägger du till följande nyckel/värde-par i en .editorconfig-fil i projektet:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Tillåtna symbolnamnformat i alternativvärdet (avgränsade med |
):
- Endast symbolnamn (innehåller alla symboler med namnet, oavsett vilken typ eller namnrymd som innehåller).
- Fullständigt kvalificerade namn i symbolens dokumentations-ID-format. Varje symbolnamn kräver ett symboltypprefix, till exempel
M:
för metoder,T:
för typer ochN:
för namnområden. .ctor
för konstruktorer och.cctor
statiska konstruktorer.
Exempel:
Alternativvärde | Sammanfattning |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Matchar alla symboler med namnet MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Matchar alla symboler med namnet antingen MyType1 eller MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Matchar en specifik metod MyMethod med den angivna fullständigt kvalificerade signaturen. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Matchar specifika metoder MyMethod1 och MyMethod2 med respektive fullständigt kvalificerade signaturer. |
Exkludera specifika typer och deras härledda typer
Du kan exkludera specifika typer och deras härledda typer från analys. Om du till exempel vill ange att regeln inte ska köras på några metoder inom typer som heter MyType
och deras härledda typer lägger du till följande nyckel/värde-par i en .editorconfig-fil i projektet:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Tillåtna symbolnamnformat i alternativvärdet (avgränsade med |
):
- Skriv endast namn (innehåller alla typer med namnet, oavsett vilken typ eller namnrymd som innehåller).
- Fullständigt kvalificerade namn i symbolens dokumentations-ID-format, med ett valfritt
T:
prefix.
Exempel:
Alternativvärde | Sammanfattning |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Matchar alla typer med namnet MyType och alla deras härledda typer. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Matchar alla typer med namnet antingen MyType1 eller MyType2 och alla deras härledda typer. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Matchar en specifik typ MyType med ett angivet fullständigt kvalificerat namn och alla dess härledda typer. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Matchar specifika typer MyType1 och MyType2 med respektive fullständigt kvalificerade namn och alla deras härledda typer. |
Relaterade regler
Exempel 1
Om du implementerar en metod som returnerar ett engångsobjekt använder du ett try/finally-block utan ett catch-block för att se till att objektet tas bort. Genom att använda ett try/finally-block tillåter du att undantag aktiveras vid felpunkten och ser till att objektet tas bort.
I metoden OpenPort1 kan anropet för att öppna ISerializable-objektet SerialPort eller anropet till SomeMethod misslyckas. En CA2000-varning utfärdas om den här implementeringen.
I metoden OpenPort2 deklareras två SerialPort-objekt och anges till null:
tempPort
, som används för att testa att metodåtgärderna lyckas.port
, som används för metodens returvärde.
tempPort
är konstruerad och öppen i ett try
block, och allt annat nödvändigt arbete utförs i samma try
block. I slutet av try
blocket tilldelas den öppnade porten till objektet port
som returneras och tempPort
objektet är inställt på null
.
Blocket finally
kontrollerar värdet tempPort
för . Om den inte är null har en åtgärd i metoden misslyckats och tempPort
stängs för att se till att alla resurser släpps. Det returnerade portobjektet innehåller det öppnade SerialPort-objektet om metodens åtgärder lyckades, eller om det blir null om en åtgärd misslyckades.
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
Exempel 2
Som standard har Visual Basic-kompilatorn alla aritmetiska operatorer som söker efter spill. Därför kan alla Visual Basic-aritmetiska åtgärder utlösa en OverflowException. Detta kan leda till oväntade överträdelser i regler som CA2000. Till exempel skapar följande CreateReader1-funktion en CA2000-överträdelse eftersom Visual Basic-kompilatorn genererar en kontrollinstruktion för spill för tillägget som kan utlösa ett undantag som skulle göra att StreamReader inte tas bort.
Du kan åtgärda detta genom att inaktivera utsändande av spillkontroller av Visual Basic-kompilatorn i projektet eller så kan du ändra koden som i följande CreateReader2-funktion.
Om du vill inaktivera utsändande av spillkontroller högerklickar du på projektnamnet i Solution Explorer och väljer sedan Egenskaper. Välj Kompilera>avancerade kompileringsalternativ och kontrollera sedan Ta bort heltalsöverflödeskontroller.
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