Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
| Proprietà | valore |
|---|---|
| ID regola | CA2000 |
| Title | Rilasciare gli oggetti prima che escano dall'ambito |
| Categoria | Affidabilità |
| La correzione causa un'interruzione o meno | Non rompente |
| Abilitato per impostazione predefinita in .NET 10 | No |
| Linguaggi applicabili | C# e Visual Basic |
Causa
Viene creato un oggetto locale di un tipo IDisposable, ma l'oggetto non viene eliminato prima che tutti i riferimenti all'oggetto escano dall'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 escano dall'ambito, l'oggetto verrà eliminato in un 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à di 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 rilasciato prima che tutti i riferimenti a esso abbiano esaurito il loro ambito.
Come correggere le violazioni
Per correggere una violazione di questa regola, chiamare Dispose sull'oggetto prima che tutti i riferimenti ad esso escano dall'ambito.
È possibile usare l'istruzione using (Using in Visual Basic) per effettuare il wrapping di oggetti che implementano IDisposable. Gli oggetti che vengono incapsulati in questo modo vengono eliminati automaticamente alla fine del blocco using. 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/finallyblocco all'esterno di unusingblocco.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 ombra per implementare il pattern dispose degli oggetti IDisposable.
Quando eliminare gli avvisi
Non eliminare un avviso da questa regola a meno che:
- Hai chiamato un metodo sul tuo oggetto che chiama
Dispose, ad esempio Close. - Il metodo che ha generato l'avviso restituisce un IDisposable oggetto che avvolge il tuo 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 e quando è necessario trasferire la proprietà dispose.
- Escludere simboli specifici
- Escludere tipi specifici e i relativi tipi derivati
- Configurare il trasferimento della proprietà dispose
Inoltre, le altre opzioni correlate all'analisi del flusso di dati seguenti si applicano a questa regola:
- dispose_analysis_kind
- interprocedural_analysis_kind
- massima_catena_di_chiamate_di_lambda_interprocedurale_o_funzione_locale
- max_interprocedural_method_call_chain
- points_to_analysis_kind
- copy_analysis
- conteggio_iterazioni_sufficiente_per_algoritmo_KDF_debole
È possibile configurare queste opzioni solo per questa regola, per tutte le regole a cui si applicano o per tutte le regole in questa categoria (Affidabilità) a cui si applicano. 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 impostando l'opzione excluded_symbol_names. 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
Nota
Sostituire la parte XXXX di CAXXXX con l'ID della regola applicabile.
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 dell'ID della documentazione del simbolo. Ogni nome di simbolo richiede un prefisso di tipo di simbolo, ad esempio
M:per i metodi,T:per i tipi eN:per i namespace. -
.ctorper costruttori e.cctorper 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) |
Abbina metodi specifici MyMethod1 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 impostando l'opzione excluded_type_names_with_derived_types. 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
Nota
Sostituire la parte XXXX di CAXXXX con l'ID della regola applicabile.
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 dei simboli, 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 |
Abbina tipi specifici MyType1 e MyType2 con i rispettivi nomi completamente qualificati e tutti i relativi tipi derivati. |
Configurare il trasferimento della proprietà dispose
Le opzioni dispose_ownership_transfer_at_constructor e dispose_ownership_transfer_at_method_call configurano il trasferimento della proprietà di dispose.
Ad esempio, per specificare che la regola trasferisce la responsabilità del dispose per gli argomenti passati ai costruttori, aggiungere la seguente coppia chiave-valore a un file .editorconfig nel progetto:
dotnet_code_quality.CAXXXX.dispose_ownership_transfer_at_constructor = true
Nota
Sostituire la parte XXXX di CAXXXX con l'ID della regola applicabile.
trasferimento_proprietà_dispose_durante_il_costruttore
Si consideri l'esempio di codice seguente.
class A : IDisposable
{
public void Dispose() { }
}
class Test
{
DisposableOwnerType M1()
{
return new DisposableOwnerType(new A());
}
}
- Se
dotnet_code_quality.dispose_ownership_transfer_at_constructorè impostato sutrue, la proprietà di rilascio per l'allocazionenew A()viene trasferita all'istanzaDisposableOwnerTyperestituita. - Se
dotnet_code_quality.dispose_ownership_transfer_at_constructorè impostato afalse,Test.M1()ha la responsabilità di eliminazione pernew A()e genera una violazione diCA2000per una perdita di risorse.
trasferimento_della_proprietà_dell'oggetto_alla_chiamata_del_metodo
Si consideri l'esempio di codice seguente.
class Test
{
void M1()
{
TransferDisposeOwnership(new A());
}
}
- Se
dotnet_code_quality.dispose_ownership_transfer_at_method_callè impostato sutrue, la proprietà dispose per l'allocazionenew A()viene trasferita al metodoTransferDisposeOwnership. - Se
dotnet_code_quality.dispose_ownership_transfer_at_method_callè impostato sufalse,Test.M1()ha la proprietà dispose pernew A()e genera una violazione diCA2000per una perdita di eliminazione.
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 di Visual Basic fa sì che tutti gli operatori aritmetici verifichino 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 seguente funzione CreateReader1 genererà una violazione CA2000 perché il compilatore di Visual Basic emette un'istruzione di controllo dell'overflow per l'addizione che potrebbe generare un'eccezione, causando così il mancato rilascio 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 degli interi.
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