Sdílet prostřednictvím


CA2000: Uvolňujte objekty před ztrátou oboru

TypeName

DisposeObjectsBeforeLosingScope

CheckId

CA2000

Kategorie

Microsoft.Reliability

Narušující změna

Nenarušující

Příčina

Je vytvořen místní objekt typu IDisposable, ale není uvolněn před tím, než jsou všechny odkazy na objekt mimo rozsah.

Popis pravidla

Pokud není jednorázový objekt explicitně odstraněn před tím, než jsou všechny odkazy mimo rozsah, bude objekt odstraněn v době, kdy bude systémem uvolňování paměti spuštěna finalizační metoda objektu.Protože může nastat mimořádná událost, která zabrání spuštění finalizační metody objektu, měl by místo toho být objekt explicitně odstraněn.

Jak vyřešit porušení

Pro vyřešení porušení tohoto pravidla je zapotřebí zavolat na objekt Dispose před tím, než jsou všechny odkazy na něj mimo rozsah.

Všimněte si, že můžete použít příkaz using (Using v Visual Basic) pro zabalení objektů, které implementují IDisposable.Objekty, které jsou zabaleny tímto způsobem budou automaticky odstraněny při uzavření bloku using.

Níže jsou některé situace, kde příkaz using nestačí k ochraně objektů IDisposable a mohou způsobit výskyt CA2000.

  • Vracení uvolnitelného objektu vyžaduje, aby byl objekt zkonstruován v rámci bloku try/finally mimo blok using.

  • Inicializace členů jednorázového objektu by neměla být provedena v rámci konstruktoru příkazu using.

  • Vnořené konstruktory, které jsou chráněny pouze jednou obslužnou rutinou výjimky.Příklad:

    using (StreamReader sr = new StreamReader(new FileStream("C:\myfile.txt", FileMode.Create)))
    { ... }
    

    způsobí výskyt CA2000, protože selhání vytvoření objektu StreamReader může vést k tomu, že objekt FileStream nebude nikdy uzavřen.

  • Dynamické objekty by měly pro implementaci vzoru odstranění objektů IDisposable používat stínový objekt.

Kdy potlačit upozornění

Nepotlačujte upozornění od tohoto pravidla, pokud jste volali metodu na objekt, který volá Dispose, jako například Close, nebo pokud metoda, která vyvolala upozornění, vrátí objekt IDisposable zabalující objekt.

Související pravidla

CA2213: Uvolnitelné pole by mělo být uvolněno

CA2202: Neuvolňujte objekty několikrát

Příklad

Při implementaci metody, která vrací uvolnitelný objekt, je zapotřebí použít blok try/finally bez použití bloku catch pro ujištění se, zda je objekt uvolněn.Pomocí bloku try/finally lze povolit vyvolání výjimek v místě selhání pro ujištění se, zda je objekt uvolněn.

V metodě OpenPort1 může volání pro otevření objektu ISerializable SerialPort nebo volání SomeMethod selhat.V této implementaci je vyvoláno upozornění CA2000.

V metodě OpenPort2 jsou deklarovány dva objekty SerialPort a jsou nastaveny na hodnotu null:

  • tempPort, který se používá k testování, zda proběhly operace metody úspěšně.

  • port, který se používá pro návratovou hodnotu metody.

tempPort je vytvořen a otevřen v rámci bloku try a jakákoliv jiná požadovaná činnost je vykonána v rámci stejného bloku try.Na konci bloku try je otevřený port přiřazen objektu port, který bude vrácen a objekt tempPort je nastaven na null.

Blok finally kontroluje hodnotu tempPort.Pokud není null, operace v rámci metody selhala a tempPort je zavřen pro ujištění se, aby nebyly uvolněny jakékoliv prostředky.Vrácený objekt portu bude obsahovat otevřený objekt SerialPort, pokud byly operace metody úspěšné nebo bude null, pokud se operace nezdaří.

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

Standardně má kompilátor Visual Basic všechny aritmetické operátory kontrolovány vůči přetečení.A proto může jakákoliv aritmetická operace jazyka Visual Basic vyvolat OverflowException.To může vést k neočekávaným porušením pravidel jako například CA2000.Například následující funkce CreateReader1 ohlásí porušení CA2000 protože kompilátor jazyka Visual Basic generuje dodatečnou instrukci kontroly přetečení, která může vyvolat výjimku, která může způsobit, že StreamReader nebude odstraněn.

Pro vyřešení toho problému lze zakázat generování kontrol přetečení kompilátorem jazyka Visual Basic v rámci projektu nebo lze provést modifikaci kódu, jak je tomu ve funkci CreateReader2.

Pro zakázání generování kontrol přetečení, klikněte pravým tlačítkem myši na název projektu v Průzkumníku řešení a poté klikněte na Vlastnosti.Klikněte na tlačítko Kompilovat, následně klikněte na Rozšířené možnosti kompilace a poté zaškrtněte Odebrat kontrolu přetečení celých čísel.

Viz také

Referenční dokumentace

IDisposable

Další zdroje

Implementing Finalize and Dispose