Share via


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 8 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:

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 ett using 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 MyTypelä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 och N: 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.

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 tempPortfö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

Se även