Condividi tramite


CA2000: Eliminare gli oggetti prima di perdere l'ambito

TypeName

DisposeObjectsBeforeLosingScope

CheckId

CA2000

Category

Microsoft.Reliability

Breaking Change

Non sostanziale

Causa

Viene creato un oggetto locale di un tipo IDisposable, ma l'oggetto non viene eliminato prima che tutti i riferimenti relativi siano esterni all'ambito.

Descrizione della regola

Se un oggetto Disposable non viene eliminato in modo esplicito prima che tutti i relativi riferimenti siano esterni all'ambito, l'oggetto verrà eliminato nel momento in cui il Garbage Collector eseguirà il finalizzatore dell'oggetto. Poiché è possibile che si verifichi un evento eccezionale che impedisca l'esecuzione del finalizzatore dell'oggetto, è opportuno eliminare in modo esplicito l'oggetto.

Come correggere le violazioni

Per correggere una violazione di questa regola, chiamare il metodo Dispose sull'oggetto prima che tutti i riferimenti relativi siano esterni all'ambito.

È possibile utilizzare l'istruzione using (Using in Visual Basic) per eseguire il wrapping di oggetti che implementano IDisposable. Gli oggetti di cui è stato eseguito questo tipo di wrapping vengono eliminati automaticamente alla chiusura del blocco using.

Le situazioni seguenti in cui l'istruzione using non è sufficiente a proteggere gli oggetti IDisposable e può comportare la generazione di CA2000.

  • La restituzione di un oggetto eliminabile richiede che l'oggetto venga costruito in un blocco try/finally esterno a un blocco using.

  • L'inizializzazione dei membri di un oggetto eliminabile non deve essere eseguita nel costruttore di un'istruzione using.

  • Costruttori di annidamento protetti solo da un gestore di eccezioni. Ad esempio,

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

    fa in modo che CA2000 venga generato perché un errore nella costruzione dell'oggetto StreamReader può impedire la chiusura dell'oggetto FileStream.

  • Gli oggetti dinamici devono utilizzare un oggetto ombreggiatura per implementare il modello Dispose degli oggetti IDisposable.

Esclusione di avvisi

Non escludere un avviso da questa regola a meno che non sia stato chiamato un metodo sull'oggetto che chiama Dispose, ad esempio Close.

Regole correlate

CA2213: I campi Disposable devono essere eliminati

CA2202: Non eliminare oggetti più volte

Esempio

Se si sta implementando un metodo che restituisce un oggetto eliminabile, utilizzare un blocco try/finally senza un blocco catch per assicurarsi che l'oggetto venga eliminato. Utilizzando un blocco try/finally, si consente la generazione di eccezioni dal punto dell'errore e si garantisce che l'oggetto venga eliminato.

Nel metodo OpenPort1, la chiamata per aprire l'oggetto ISerializable SerialPort o la chiamata a SomeMethod può avere esito negativo. Viene generato un avviso CA2000 nell'implementazione.

Nel metodo OpenPort2, due oggetti SerialPort vengono dichiarati e impostati come null:

  • tempPort, utilizzato per verificare l'esito positivo delle operazioni del metodo.

  • port, utilizzato per il valore restituito del metodo.

tempPort viene costruito e aperto in un blocco try e qualsiasi altra operazione richiesta viene eseguita nello stesso blocco try. Alla fine del blocco try, la porta aperta viene assegnata all'oggetto port che verrà restituito e l'oggetto tempPort viene impostato su null.

Il blocco finally verifica il valore di tempPort. Se non è null, un'operazione nel metodo ha avuto esito negativo e tempPort viene chiuso per garantire il rilascio delle risorse. L'oggetto porta restituito conterrà l'oggetto SerialPort aperto se le operazioni del metodo sono riuscite, o sarà null se un'operazione non è riuscita.

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

Per impostazione predefinita, nel compilatore Visual Basic tutti gli operatori aritmetici consentono di verificare l'overflow. Pertanto, qualsiasi operazione aritmetica di Visual Basic potrebbe generare un oggetto OverflowException. Ciò può condurre a violazioni impreviste di regole, come ad esempio CA2000. Ad esempio, nella funzione CreateReader1 seguente sarà prodotta una violazione CA2000 perché il compilatore Visual Basic sta generando un'istruzione del controllo dell'overflow per l'aggiunta, la quale potrebbe generare un'eccezione che impedirebbe la collocazione di StreamReader.

Per correggere, è possibile disabilitare l'emissione di controlli dell'overflow dal compilatore Visual Basic nel progetto o è possibile modificare il codice come la funzione CreateReader2 seguente.

Per disabilitare l'emissione dei controlli di overflow, in Esplora soluzioni fare clic con il pulsante destro del mouse sul nome del progetto, quindi fare clic su Proprietà. Fare clic su Compila, fare clic su Opzioni di compilazione avanzate, quindi controllare Rimuovi controllo dell'overflow di Integer.

Vedere anche

Riferimenti

IDisposable

Implementazione dei metodi Finalize e Dispose per la pulizia delle risorse non gestite