CA2000: Objektumokat szabadít fel a hatókör elvesztése előtt

Tulajdonság Érték
Szabályazonosító CA2000
Cím Objektumok eltávolítása a hatókörből való kilépés előtt
Kategória Megbízhatóság
A javítás romboló vagy nem romboló Nem törhető
Alapértelmezés szerint engedélyezve a .NET 10-ben Nem
Alkalmazandó nyelvek C# és Visual Basic

Ok

Létrejön egy IDisposable helyi típusú objektum, de az objektum nem lesz megsemmisítve, mielőtt az objektumra mutató összes hivatkozás hatókörön kívül esik.

Ez a szabály alapértelmezés szerint a teljes kódbázist elemzi, de ez konfigurálható.

Szabály leírása

Ha egy eldobható objektum nincs explicit módon megsemmisítve, mielőtt az összes rá mutató hivatkozás hatókörön kívül lenne, az objektumot meghatározatlan időpontban kell megsemmisíteni, amikor a szemétgyűjtő futtatja az objektum véglegesítőjét. Mivel előfordulhat olyan kivételes esemény, amely megakadályozza az objektum véglegesítőjének futását, az objektumot explicit módon kell megsemmisíteni.

Különleges esetek

A CA2000 szabály akkor sem aktiválja az alábbi típusú helyi objektumokat, ha az objektum nincs megsemmisítve:

Ha egy ilyen típusú objektumot átad egy konstruktor paramétereként, majd hozzárendeli egy mezőhöz, ez azt jelenti, hogy a felelősség az erőforrások felszabadításáért az újonnan létrehozott típusra száll át. Vagyis az újonnan létrehozott típus felelős az objektum eltávolításáért. Ha a kód átad egy ilyen típusú objektumot egy konstruktornak, akkor a CA2000 szabály megsértése akkor sem történik meg, ha az objektum nincs megsemmisítve, mielőtt az összes hivatkozás hatókörén kívül lenne.

Szabálysértések kijavítása

A szabály megsértésének kijavításához hívja meg Dispose az objektumot, mielőtt az összes rá mutató hivatkozás hatókörön kívül lenne.

A using utasítással (Using a Visual Basicben) körbefuttathatja azokat az objektumokat, amelyek megvalósítják a IDisposable-ot. Az ilyen módon burkolt objektumok a csoport végén automatikusan megsemmisítve lesznek. A következő helyzeteket azonban nem, vagy nem lehet utasítással using kezelni:

  • Egy eldobható objektum visszaadásához az objektumot a try/finally blokkban kell létrehozni, azon kívül eső using blokkon kívül.

  • Ne inicializálja egy eldobható objektum tagjait a using utasítás konstruktorában.

  • Ha a csak egy kivételkezelő által védett konstruktorok egy using utasítás beszerzési részében vannak beágyazva, a külső konstruktor meghibásodása azt eredményezheti, hogy a beágyazott konstruktor által létrehozott objektum soha nem lesz bezárva. Az alábbi példában a StreamReader konstruktor meghibásodása azt eredményezheti, hogy az FileStream objektum soha nem lesz bezárva. A CA2000 ebben az esetben a szabály megsértését jelöli.

    using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create)))
    { ... }
    
  • A dinamikus objektumoknak árnyékobjektumot kell használniuk az IDisposable eldobási minta megvalósításához.

Mikor kell letiltani a figyelmeztetéseket?

Ne nyomja el a szabály figyelmeztetését, kivéve, ha:

  • Olyan metódust hívott meg az objektumon, amely meghívja a(z) Dispose, például a(z) Close.
  • A figyelmeztetést generáló metódus egy IDisposable objektumot ad vissza, amely becsomagolja az objektumot.
  • Az allokálási módszer nem biztosít felszabadítási tulajdonjogot; azaz az objektum felszabadításának felelőssége egy másik, a metódusban létrehozott és a hívónak visszaadott objektumra vagy burkolóra száll át.

Figyelmeztetés mellőzése

Ha csak egyetlen szabálysértést szeretne letiltani, adjon hozzá előfeldolgozási irányelveket a forrásfájlhoz a szabály letiltásához és újbóli engedélyezéséhez.

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

Ha le szeretné tiltani egy fájl, mappa vagy projekt szabályát, állítsa annak súlyosságát none a konfigurációs fájlban.

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

További információ: Kódelemzési figyelmeztetések letiltása.

Kód konfigurálása elemzéshez

Az alábbi beállításokkal konfigurálhatja, hogy a kódbázis mely részein futtassa ezt a szabályt, és mikor kell átadni a tulajdonjogot.

Emellett a következő, adatfolyam-elemzéssel kapcsolatos lehetőségek is érvényesek erre a szabályra:

Ezeket a beállításokat konfigurálhatja csak erre a szabályra, az összes szabályra, vagy az ebben a kategóriában szereplő összes szabályra (Megbízhatósági), amelyekre vonatkoznak. További információ: Kódminőségi szabály konfigurációs beállításai.

Adott szimbólumok kizárása

A excluded_symbol_names beállítással kizárhat bizonyos szimbólumokat, például típusokat és metódusokat az elemzésből. Ha például meg szeretné adni, hogy a szabály ne fusson a nevesített MyTypetípusok egyikén sem, adja hozzá a következő kulcs-érték párot a projekt egyik .editorconfig fájljához:

dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType

Jegyzet

Cserélje le a XXXXCAXXXX részét a vonatkozó szabály azonosítójára.

Engedélyezett szimbólumnévformátumok a beállításértékben (a következővel |elválasztva):

  • Csak szimbólumnév (a névvel ellátott összes szimbólumot tartalmazza, függetlenül attól, hogy milyen típusú vagy névtérrel rendelkezik).
  • A szimbólum "dokumentációazonosító formátumában" szereplő teljes nevek. Minden szimbólumnévhez szimbólum típusú előtag szükséges, például M: metódusokhoz, T: típusokhoz és N: névterekhez.
  • .ctor konstruktorok és .cctor statikus konstruktorok számára.

Példák:

Beállítás értéke Összegzés
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType Megegyezik az összes elnevezett MyTypeszimbólummal.
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 Az összes MyType1 vagy MyType2 nevű szimbólummal megegyezik.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) Megfelel a megadott metódusnak MyMethod a megadott teljes jogosultsággal rendelkező aláírással.
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) Összepárosítja az adott metódusokat MyMethod1 és MyMethod2 a megfelelő teljesen minősített aláírásokkal.

Adott típusok és származtatott típusok kizárása

A excluded_type_names_with_derived_types beállítás beállításával kizárhat bizonyos típusokat és azok származtatott típusait az elemzésből. Ha például meg szeretné adni, hogy a szabály ne fusson a nevesített MyType és származtatott típusok egyik metódusán sem, adja hozzá a következő kulcs-érték párot a projekt egyik .editorconfig fájljához:

dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType

Jegyzet

Cserélje le a XXXXCAXXXX részét a vonatkozó szabály azonosítójára.

Engedélyezett szimbólumnévformátumok a beállításértékben (a következővel |elválasztva):

  • Csak típusnév (a névvel rendelkező összes típust tartalmazza, függetlenül attól, hogy milyen típust vagy névteret tartalmaz).
  • A szimbólum dokumentációazonosító formátumában található teljesen minősített nevek, opcionális T: előtaggal.

Példák:

Beállítás értéke Összegzés
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType Megfelel az összes névvel ellátott MyType típusnak és az összes származtatott típusnak.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 Megfelel minden olyan típusnak, amelyik vagy a MyType1 vagy a MyType2 nevet viseli, és az összes belőlük származtatott típusnak.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType Az adott MyType típust egyezteti a megadott teljes névvel és az összes származtatott típusával.
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 Az MyType1 és MyType2 konkrét típusokat és azoknak a teljes kvalifikált neveket, valamint az összes származtatott típust egyezteti.

Tulajdonjog-átruházás konfigurálása

A dispose_ownership_transfer_at_constructor és a dispose_ownership_transfer_at_method_call opciók a rendelkezési jog átruházását konfigurálják.

Ha például meg szeretné adni, hogy a szabályátadások a konstruktoroknak átadott argumentumok tulajdonjogát adják át, adja hozzá a következő kulcs-érték párot egy .editorconfig fájlhoz a projektben:

dotnet_code_quality.CAXXXX.dispose_ownership_transfer_at_constructor = true

Jegyzet

Cserélje le a XXXXCAXXXX részét a vonatkozó szabály azonosítójára.

tulajdonjog_átadás_konstruktorban

Tekintse meg a következő kód példáját.

class A : IDisposable
{
    public void Dispose() { }
}

class Test
{
    DisposableOwnerType M1()
    {
        return new DisposableOwnerType(new A());
    }
}
  • Ha dotnet_code_quality.dispose_ownership_transfer_at_constructortrueértékre van állítva, a rendszer a new A() lefoglalás tulajdonjogát a visszaadott DisposableOwnerType példányra továbbítja.
  • Ha dotnet_code_quality.dispose_ownership_transfer_at_constructorfalse van beállítva, Test.M1() rendelkezik a new A() kezelésének jogával, és CA2000 szabálytalanságot eredményez egy erőforrás-szivárgás miatt.

tulajdon_átadás_megsemmisítés_metódushíváskor

Tekintse meg a következő kód példáját.

class Test
{
    void M1()
    {
        TransferDisposeOwnership(new A());
    }
}
  • Ha dotnet_code_quality.dispose_ownership_transfer_at_method_calltrueértékre van állítva, a new A() lefoglalás tulajdonjogának átruházása a TransferDisposeOwnership metódusba történik.
  • Ha dotnet_code_quality.dispose_ownership_transfer_at_method_callfalse van beállítva, akkor Test.M1() rendelkezik a new A() megsemmisítési jogosultsággal, és ez CA2000 jogsértést eredményez a megsemmisítési szivárgás miatt.

1. példa

Ha olyan metódust implementál, amely felszabadítható objektumot ad vissza, használjon egy try/finally blokkot fogási blokk nélkül, hogy az objektum felszabadítása biztosítva legyen. Egy try/finally blokk használatával lehetővé teszi, hogy a kivétel a hibaponthoz vezető úton keletkezzen, ezzel biztosítva, hogy az objektum megfelelően fel legyen szabadítva.

Az OpenPort1 metódusban az ISerializable objektumot, a SerialPort-ot nem sikerül megnyitni, vagy a SomeMethod hívása sikertelen lehet. A megvalósítás során CA2000 figyelmeztetés jelenik meg.

Az OpenPort2 metódusban két SerialPort-objektum deklarálva van, és null értékre van állítva:

  • tempPort, amely a metódusműveletek sikerességét teszteli.

  • port, amelyet a metódus visszatérési értékéhez használnak.

A tempPort blokk egy try blokkban van létrehozva és megnyitva, és minden más szükséges munka ugyanabban try a blokkban történik. A blokk végén a megnyitott portot a port objektumhoz rendelik, és az objektum visszaadásra kerül, az tempPort objektumot pedig beállítják null értékre.

A finally blokk ellenőrzi a következő értékét tempPort: . Ha nem null értékű, a metódus egyik művelete sikertelen volt, és tempPort bezárva van, hogy meggyőződjön arról, hogy az erőforrások felszabadulnak. A visszaadott portobjektum a megnyitott SerialPort objektumot fogja tartalmazni, ha a metódus műveletei sikeresek, vagy null értékű lesz, ha egy művelet meghiúsult.

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

2. példa

Alapértelmezés szerint a Visual Basic fordítóban minden számtani operátor ellenőrzi a túlcsordulást. Ezért bármely Visual Basic-aritmetikai művelet dobhat egy OverflowException. Ez olyan szabályok váratlan megsértéséhez vezethet, mint a CA2000. Az alábbi CreateReader1 függvény például CA2000-es szabálysértést eredményez, mert a Visual Basic fordító túlcsordulás-ellenőrzési utasítást bocsát ki az összeadáshoz, amely kivételt okozhat, amely miatt a StreamReader nem lesz megsemmisítve.

Ennek kijavításához letilthatja a Visual Basic fordító által a projektben végzett túlcsordulás-ellenőrzések kibocsátását, vagy módosíthatja a kódot az alábbi CreateReader2 függvényhez hasonlóan.

A túlcsordulás-ellenőrzések kibocsátásának letiltásához kattintson a jobb gombbal a projekt nevére Megoldáskezelő, majd válassza a Tulajdonságok lehetőséget. Válassza a Fordítás>Speciális fordítási beállítások lehetőséget, majd jelölje be az egész szám túlcsordulási ellenőrzéseinek eltávolítása.

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

Lásd még