CA2000 : Supprimer les objets avant la mise hors de portée
Propriété | Value |
---|---|
Identificateur de la règle | CA2000 |
Titre | Supprimer les objets avant la mise hors de portée |
Catégorie | Fiabilité |
Le correctif est cassant ou non cassant | Sans rupture |
Activé par défaut dans .NET 8 | Non |
Cause
Un objet local d’un type IDisposable est créé, mais l’objet n’est pas supprimé avant que toutes les références à l’objet ne soient hors de portée.
Par défaut, cette règle analyse l’intégralité du codebase, mais elle est configurable.
Description de la règle
Si un objet supprimable n’est pas explicitement supprimé avant que toutes les références à celui-ci ne soient hors de portée, l’objet est supprimé à un moment indéterminé quand le récupérateur de mémoire exécute le finaliseur de l’objet. Comme un événement exceptionnel peut se produire et empêcher l’exécution du finaliseur de l’objet, ce dernier doit au lieu de cela être supprimé explicitement.
Cas particuliers
La règle CA2000 ne se déclenche pas pour les objets locaux des types suivants, même si l’objet n’est pas supprimé :
- System.IO.Stream
- System.IO.StringReader
- System.IO.TextReader
- System.IO.TextWriter
- System.Resources.IResourceReader
Le passage d’un objet d’un de ces types à un constructeur, puis son affectation à un champ indique un transfert de la propriété de suppression vers le type nouvellement construit. Autrement dit, le type nouvellement construit est maintenant responsable de la suppression de l’objet. Si votre code passe un objet de l’un de ces types à un constructeur, aucune violation de la règle CA2000 ne se produit, même si l’objet n’est pas supprimé avant que toutes les références à celui-ci ne soient hors de portée.
Comment corriger les violations
Pour corriger une violation de cette règle, appelez Dispose sur l’objet avant que toutes les références à celui-ci ne soient hors de portée.
Vous pouvez utiliser l’instruction using
(Using
en Visual Basic) pour encapsuler des objets qui implémentent IDisposable. Les objets qui sont encapsulés de cette manière sont automatiquement supprimés à la fin du bloc using
. Cependant, les situations suivantes ne doivent pas ou ne peuvent pas être gérées avec une instruction using
:
Pour retourner un objet supprimable, l’objet doit être construit dans un bloc
try/finally
en dehors d’un blocusing
.N’initialisez pas les membres d’un objet supprimable dans le constructeur d’une instruction
using
.Quand des constructeurs protégés par un seul gestionnaire d’exceptions sont imbriqués dans la partie acquisition d’une instruction
using
, une défaillance du constructeur externe peut faire que l’objet créé par le constructeur imbriqué n’est jamais fermé. Dans l’exemple suivant, une défaillance dans le constructeur StreamReader peut faire que l’objet FileStream n’est jamais fermé. CA2000 signale dans ce cas une violation de la règle.using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create))) { ... }
Les objets dynamiques doivent utiliser un objet fantôme pour implémenter le modèle de suppression d’objets IDisposable.
Quand supprimer les avertissements
Ne supprimez pas un avertissement de cette règle sauf si :
- Vous avez appelé une méthode sur votre objet qui appelle
Dispose
, comme Close. - La méthode qui a déclenché l’avertissement retourne un objet IDisposable qui encapsule votre objet.
- La méthode d’allocation n’a pas de propriété de suppression, c’est-à-dire que la responsabilité de supprimer l’objet est transférée à un autre objet ou un autre wrapper créé dans la méthode et retourné à l’appelant.
Supprimer un avertissement
Si vous voulez supprimer une seule violation, ajoutez des directives de préprocesseur à votre fichier source pour désactiver et réactiver la règle.
#pragma warning disable CA2000
// The code that's violating the rule is on this line.
#pragma warning restore CA2000
Pour désactiver la règle sur un fichier, un dossier ou un projet, définissez sa gravité sur none
dans le fichier de configuration.
[*.{cs,vb}]
dotnet_diagnostic.CA2000.severity = none
Pour plus d’informations, consultez Comment supprimer les avertissements de l’analyse de code.
Configurer le code à analyser
Utilisez l’option suivante pour configurer les parties de votre codebase sur lesquelles exécuter cette règle.
Vous pouvez configurer ces options pour cette règle uniquement, pour toutes les règles auxquelles elles s’appliquent ou pour toutes les règles de cette catégorie (Fiabilité) auxquelles elles s’appliquent. Pour plus d’informations, consultez Options de configuration des règles de qualité du code.
Exclure des symboles spécifiques
Vous pouvez exclure de l’analyse des symboles spécifiques, comme des types et des méthodes. Par exemple, pour spécifier que la règle ne doit pas s’exécuter sur du code dans des types nommés MyType
, ajoutez la paire clé-valeur suivante à un fichier .editorconfig dans votre projet :
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType
Formats de nom de symbole autorisés dans la valeur d’option (séparés par |
) :
- Nom du symbole uniquement (inclut tous les symboles avec le nom, quel que soit le type ou l’espace de noms qui les contient).
- Noms qualifiés complets au format d’ID de documentation du symbole. Chaque nom de symbole nécessite un préfixe de type symbole, comme
M:
pour les méthodes,T:
pour les types etN:
pour les espaces de noms. .ctor
pour les constructeurs et.cctor
pour les constructeurs statiques.
Exemples :
Valeur d’option | Récapitulatif |
---|---|
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType |
Correspond à tous les symboles nommés MyType . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = MyType1|MyType2 |
Correspond à tous les symboles nommés MyType1 ou MyType2 . |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS.MyType.MyMethod(ParamType) |
Correspond à une méthode MyMethod spécifique avec la signature complète spécifiée. |
dotnet_code_quality.CAXXXX.excluded_symbol_names = M:NS1.MyType1.MyMethod1(ParamType)|M:NS2.MyType2.MyMethod2(ParamType) |
Correspond à des méthodes MyMethod1 et MyMethod2 spécifiques avec la signature complète spécifiée. |
Exclure des types spécifiques et leurs types dérivés
Vous pouvez exclure de l’analyse des types spécifiques et leurs types dérivés. Par exemple, pour spécifier que la règle ne doit s’exécuter sur aucune méthode dans des types nommés MyType
et leurs types dérivés, ajoutez la paire clé-valeur suivante à un fichier .editorconfig dans votre projet :
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType
Formats de nom de symbole autorisés dans la valeur d’option (séparés par |
) :
- Nom du type uniquement (inclut tous les types avec le nom, quel que soit le type ou l’espace de noms qui les contient).
- Noms qualifiés complets au format d’ID de documentation du symbole, avec un préfixe
T:
facultatif.
Exemples :
Valeur d’option | Récapitulatif |
---|---|
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType |
Correspond à tous les types nommés MyType et à tous leurs types dérivés. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = MyType1|MyType2 |
Correspond à tous les types nommés MyType1 ou MyType2 , et à tous leurs types dérivés. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS.MyType |
Correspond à un type MyType spécifique avec un nom complet donné et tous ses types dérivés. |
dotnet_code_quality.CAXXXX.excluded_type_names_with_derived_types = M:NS1.MyType1|M:NS2.MyType2 |
Correspond à des types MyType1 ou MyType2 spécifiques avec leur nom complet respectif et tous leurs types dérivés. |
Règles associées
Exemple 1
Si vous implémentez une méthode qui retourne un objet supprimable, utilisez un bloc try/finally sans bloc catch pour être sûr que l’objet est supprimé. En utilisant un bloc try/finally, vous permettez la levée d’exceptions au point d’erreur et vous êtes sûr vous que l’objet est supprimé.
Dans la méthode OpenPort1, l’appel pour ouvrir l’objet SerialPort ISerializable ou l’appel à SomeMethod peut échouer. Un avertissement CA2000 est déclenché sur cette implémentation.
Dans la méthode OpenPort2, deux objets SerialPort sont déclarés et définis sur null :
tempPort
, qui est utilisé pour tester la réussite des opérations de méthode.port
, qui est utilisé pour la valeur de retour de la méthode.
Le tempPort
est construit et ouvert dans un bloc try
, et tout autre travail nécessaire est effectué dans le même bloc try
. À la fin du bloc try
, le port ouvert est affecté à l’objet port
qui sera retourné et l’objet tempPort
est défini sur null
.
Le bloc finally
vérifie la valeur de tempPort
. S’il n’est pas null, c’est qu’une opération dans la méthode a échoué et tempPort
est fermé pour être sûr toutes les ressources sont libérées. L’objet de port retourné contiendra l’objet SerialPort ouvert si les opérations de la méthode ont réussi, ou il sera null en cas d’échec d’une opération.
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
Exemple 2
Par défaut, le compilateur Visual Basic implémente la vérification du dépassement de capacité de tous les opérateurs arithmétiques. Par conséquent, toute opération arithmétique Visual Basic peut lever une OverflowException. Ceci peut entraîner des violations inattendues dans des règles comme CA2000. Par exemple, la fonction CreateReader1 suivante va générer une violation de CA2000, car le compilateur Visual Basic émet une instruction de vérification de dépassement de capacité pour l’addition qui pourrait lever une exception susceptible d’entraîner la non-suppression de StreamReader.
Pour résoudre ce problème, vous pouvez désactiver l’émission des vérifications de dépassement de capacité par le compilateur Visual Basic dans votre projet ou modifier votre code comme dans la fonction CreateReader2 suivante.
Pour désactiver l’émission des vérifications de dépassement de capacité, cliquez avec le bouton droit sur le nom du projet dans Explorateur de solutions, puis sélectionnez Propriétés. Sélectionnez Compiler>Options de compilation avancées, puis cochez Supprimer les vérifications de dépassement de capacité des entiers.
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