CA2000: Eliminare gli oggetti prima di perdere l'ambito
Proprietà | valore |
---|---|
ID regola | CA2000 |
Title | Eliminare gli oggetti prima che siano esterni all'ambito |
Categoria | Affidabilità |
La correzione causa un'interruzione o meno | Non causa un'interruzione |
Abilitato per impostazione predefinita in .NET 9 | No |
Causa
Viene creato un oggetto locale di un IDisposable tipo, ma l'oggetto non viene eliminato prima che tutti i riferimenti all'oggetto non siano nell'ambito.
Per impostazione predefinita, questa regola analizza l'intera codebase, ma è configurabile.
Descrizione regola
Se un oggetto eliminabile non viene eliminato in modo esplicito prima che tutti i riferimenti a esso non siano inclusi nell'ambito, l'oggetto verrà eliminato in un determinato momento indeterminato quando il Garbage Collector esegue il finalizzatore dell'oggetto. Poiché potrebbe verificarsi un evento eccezionale che impedirà l'esecuzione del finalizzatore dell'oggetto, l'oggetto deve essere eliminato in modo esplicito.
Casi speciali
La regola CA2000 non viene attivata per gli oggetti locali dei tipi seguenti anche se l'oggetto non viene eliminato:
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Il passaggio di un oggetto di uno di questi tipi a un costruttore e quindi l'assegnazione a un campo indica un trasferimento di proprietà dispose al tipo appena costruito. Ovvero, il tipo appena costruito è ora responsabile dell'eliminazione dell'oggetto. Se il codice passa un oggetto di uno di questi tipi a un costruttore, non si verifica alcuna violazione della regola CA2000 anche se l'oggetto non viene eliminato prima che tutti i riferimenti a esso non siano inclusi nell'ambito.
Come correggere le violazioni
Per correggere una violazione di questa regola, chiamare Dispose sull'oggetto prima che tutti i riferimenti ad esso non siano nell'ambito.
È possibile usare l'istruzione ( in Visual Basic) per eseguire il using
wrapping di oggetti che implementano IDisposableUsing
. Gli oggetti di cui viene eseguito il wrapping in questo modo vengono eliminati automaticamente alla fine del using
blocco. Tuttavia, le situazioni seguenti non devono essere gestite o non possono essere gestite con un'istruzione using
:
Per restituire un oggetto eliminabile, l'oggetto deve essere costruito in un
try/finally
blocco all'esterno di unusing
blocco.Non inizializzare i membri di un oggetto eliminabile nel costruttore di un'istruzione
using
.Quando i costruttori protetti da un solo gestore eccezioni sono annidati nella parte di acquisizione di un'istruzione
using
, un errore nel costruttore esterno può comportare l'impossibilità di chiudere l'oggetto creato dal costruttore annidato. Nell'esempio seguente un errore nel StreamReader costruttore può comportare la mancata chiusura dell'oggetto FileStream . CA2000 contrassegna una violazione della regola in questo caso.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
Gli oggetti dinamici devono usare un oggetto shadow per implementare il modello dispose di IDisposable oggetti.
Quando eliminare gli avvisi
Non eliminare un avviso da questa regola a meno che:
- È stato chiamato un metodo sull'oggetto che chiama
Dispose
, ad esempio Close. - Il metodo che ha generato l'avviso restituisce un IDisposable oggetto che esegue il wrapping dell'oggetto.
- Il metodo di allocazione non dispone della proprietà dispose; ovvero la responsabilità di eliminare l'oggetto viene trasferito a un altro oggetto o wrapper creato nel metodo e restituito al chiamante.
Eliminare un avviso
Se si vuole eliminare una singola violazione, aggiungere direttive del preprocessore al file di origine per disabilitare e quindi riabilitare la regola.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
Per disabilitare la regola per un file, una cartella o un progetto, impostarne la gravità none
su nel file di configurazione.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
Per altre informazioni, vedere Come eliminare gli avvisi di analisi del codice.
Configurare il codice da analizzare
Usare le opzioni seguenti per configurare le parti della codebase in cui eseguire questa regola.
È possibile configurare queste opzioni solo per questa regola, per tutte le regole a cui si applica o per tutte le regole in questa categoria (affidabilità) a cui si applica. Per altre informazioni, vedere Opzioni di configurazione delle regole di qualità del codice.
Escludere simboli specifici
È possibile escludere simboli specifici, ad esempio tipi e metodi, dall'analisi. Ad esempio, per specificare che la regola non deve essere eseguita in alcun codice all'interno di tipi denominati MyType
, aggiungere la coppia chiave-valore seguente a un file con estensione editorconfig nel progetto:
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Formati di nome simbolo consentiti nel valore dell'opzione (separati da |
):
- Solo nome simbolo (include tutti i simboli con il nome, indipendentemente dal tipo o dallo spazio dei nomi contenitore).
- Nomi completi nel formato ID della documentazione del simbolo. Ogni nome di simbolo richiede un prefisso di tipo simbolo, ad esempio
M:
per i metodi,T:
per i tipi eN:
per gli spazi dei nomi. .ctor
per costruttori e.cctor
per costruttori statici.
Esempi:
Valore opzione | Riepilogo |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Corrisponde a tutti i simboli denominati MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Corrisponde a tutti i simboli denominati MyType1 o MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Corrisponde a un metodo MyMethod specifico con la firma completa specificata. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Trova la corrispondenza con metodi MyMethod1 specifici e MyMethod2 con le rispettive firme complete. |
Escludere tipi specifici e i relativi tipi derivati
È possibile escludere tipi specifici e i relativi tipi derivati dall'analisi. Ad esempio, per specificare che la regola non deve essere eseguita in alcun metodo all'interno di tipi denominati MyType
e dei relativi tipi derivati, aggiungere la coppia chiave-valore seguente a un file con estensione editorconfig nel progetto:
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Formati di nome simbolo consentiti nel valore dell'opzione (separati da |
):
- Solo nome di tipo (include tutti i tipi con il nome, indipendentemente dal tipo o dallo spazio dei nomi contenitore).
- Nomi completi nel formato ID della documentazione del simbolo, con un prefisso facoltativo
T:
.
Esempi:
Valore opzione | Riepilogo |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Corrisponde a tutti i tipi denominati MyType e a tutti i relativi tipi derivati. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Corrisponde a tutti i tipi denominati MyType1 o MyType2 e a tutti i relativi tipi derivati. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Corrisponde a un tipo MyType specifico con il nome completo specificato e tutti i relativi tipi derivati. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Corrisponde a tipi MyType1 specifici e MyType2 con i rispettivi nomi completi e tutti i relativi tipi derivati. |
Regole correlate
Esempio 1
Se si implementa un metodo che restituisce un oggetto eliminabile, usare un blocco try/finally senza un blocco catch per assicurarsi che l'oggetto venga eliminato. Usando un blocco try/finally, è possibile generare eccezioni nel punto di errore e assicurarsi che l'oggetto venga eliminato.
Nel metodo OpenPort1 la chiamata per aprire l'oggetto ISerializable SerialPort o la chiamata a SomeMethod può non riuscire. In questa implementazione viene generato un avviso CA2000.
Nel metodo OpenPort2 vengono dichiarati due oggetti SerialPort e impostati su null:
tempPort
, usato per verificare che le operazioni del metodo abbiano esito positivo.port
, utilizzato per il valore restituito del metodo .
L'oggetto tempPort
viene costruito e aperto in un try
blocco e qualsiasi altro lavoro necessario viene eseguito nello stesso try
blocco. Alla fine del try
blocco, la porta aperta viene assegnata all'oggetto port
che verrà restituito e l'oggetto tempPort
è impostato su null
.
Il finally
blocco controlla il valore di tempPort
. Se non è Null, un'operazione nel metodo non è riuscita e tempPort
viene chiusa per assicurarsi che tutte le risorse vengano rilasciate. L'oggetto porta restituito conterrà l'oggetto SerialPort aperto se le operazioni del metodo sono riuscite oppure sarà Null se un'operazione non è riuscita.
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
Esempio 2
Per impostazione predefinita, il compilatore Visual Basic dispone di tutti gli operatori aritmetici che controllano l'overflow. Pertanto, qualsiasi operazione aritmetica di Visual Basic potrebbe generare un'eccezione OverflowException. Ciò potrebbe causare violazioni impreviste nelle regole, ad esempio CA2000. Ad esempio, la funzione CreateReader1 seguente genererà una violazione CA2000 perché il compilatore di Visual Basic genera un'istruzione di controllo dell'overflow per l'aggiunta che potrebbe generare un'eccezione che causerebbe l'eliminazione di StreamReader.
Per risolvere questo problema, è possibile disabilitare l'emissione di controlli di overflow dal compilatore Visual Basic nel progetto oppure modificare il codice come nella funzione CreateReader2 seguente.
Per disabilitare l'emissione di controlli di overflow, fare clic con il pulsante destro del mouse sul nome del progetto in Esplora soluzioni e quindi scegliere Proprietà. Selezionare Compila opzioni di compilazione avanzate e quindi selezionare >Rimuovi controlli di overflow integer.
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