Y a-t-il des cas particuliers où je devrais (ou ne devrais pas?) Utiliser des blocs "using":
using(SomeType t = new SomeType()){
...
}
Lorsque la classe SomeType
implémente IDisposable
.
Certains objets nécessitent une action lorsque vous en avez terminé avec eux. Cela est généralement dû au fait que l'objet utilise une sorte de ressource qui doit être supprimée. Par exemple, si vous avez un objet fichier de classe Fichier et que cet objet ouvre un fichier à partir du système de fichiers, le fichier dans le système de fichiers devra être refermé.
Si vous venez de quitter l'objet fichier et oubliez d'appeler file.Close (), il ne sera pas nettoyé tant que le garbage collector (GC) ne fonctionnera et ne fonctionnera plus si rien n'utilisait toujours l'objet fichier. Le moment où le Garbage Collector s'exécute doit être laissé au Common Language Runtime (CLR) pour décider. Si le GC ne fonctionne pas pendant un certain temps après avoir terminé avec le fichier, le fichier peut rester ouvert potentiellement pendant longtemps. Cela peut poser un gros problème s'il existe de nombreux objets fichier, ou si quelque chose veut ouvrir un fichier, mais ne le peut pas car l'objet fichier que vous avez laissé traîne toujours.
Pour résoudre ce problème, C # possède l'interface IDisposable. Cela a une méthode appelée Dispose. Les classes qui nécessitent un nettoyage implémentent cette méthode Dispose. Cela vous donne un moyen standard de nettoyer tous les objets qui utilisent des ressources. Il y a beaucoup de classes qui doivent appeler Dispose. Le problème avec cela est que le code est couvert d'appels à Dispose, et ils sont difficiles à suivre car l'endroit où vous avez créé l'objet et appelé Dispose pour le nettoyer sont différents. Donc, vous avez dû beaucoup regarder autour du code et faire très attention à vérifier qu'il y avait des appels à Dispose au bon endroit.
Pour résoudre ce problème, C # a introduit le mot clé "using". Vous pouvez placer un mot-clé "using" à l'endroit où vous créez un nouvel objet, ce qui garantit que Dispose sera appelé dessus pour vous. Il garantit que Dispose sera appelé quoi qu'il arrive ... même s'il y a une exception levée dans le corps de l'instruction using.
Donc, vous devez utiliser "using" lorsque vous voulez être sûr qu'un objet qui alloue des ressources sera nettoyé.
using ne peut être utilisé que pour les objets déclarés sur la pile, c'est-à-dire dans une fonction. Cela ne fonctionne pas pour les objets déclarés comme membres d'une classe. Pour eux, vous devez appeler Dispose yourself. Vous devrez peut-être implémenter Dispose dans votre classe afin que in puisse appeler Dispose sur tous les objets membres qu'il possède et qui le nécessitent.
Les objets courants devant être appelés sont les suivants: fichiers, connexions à la base de données, objets graphiques tels que stylo et pinceau.
Parfois, il est également utilisé lorsque vous souhaitez que deux opérations se déroulent ensemble. Par exemple, si vous souhaitez écrire une instruction de journal lorsqu'un bloc de code est entré et lorsqu'il se termine, vous pouvez écrire une classe de journal que vous pouvez utiliser comme ceci:
using( Log log = new Log("Doing stuff") )
{
// Stuff
}
Le constructeur de la classe log pourrait être fait pour écrire le message, et la méthode Dispose pourrait également l'écrire. Implémentez le finaliseur (~ Log) pour affirmer si la méthode Dispose n'est pas appelée pour garantir que "l'utilisation" est mémorisée dans le "nouveau journal".
Utilisez using
chaque fois que le type implémente IDisposable
, à moins que vous ne l'enveloppiez dans un try
/catch
bloc de toute façon, vous pourriez aussi bien (selon l'apparence que vous préférez) utiliser un bloc finally
.
Je vois beaucoup d'autres réponses indiquées lorsque vous devriez avoir une instruction using
. Je veux savoir quand spécifiquement pas avoir une instruction using
:
Si vous devez utiliser votre objet en dehors de la portée de la fonction actuelle, ne disposez pas d'un bloc using
. Un bon exemple est une méthode d'usine qui renvoie une connexion à une base de données ou une méthode qui doit renvoyer un datareader. Dans l'un ou l'autre de ces cas, si vous créez votre objet avec une instruction using
, il sera supprimé avant le retour de la méthode et ne sera donc pas utilisable en dehors de la méthode.
Maintenant, vous voulez toujours être sûr que ces objets sont supprimés, vous pouvez donc toujours vouloir une instruction using
quelque part. Il suffit de ne pas l'inclure dans la méthode où l'objet est réellement créé. Au lieu de cela, vous pouvez encapsuler l'appel de fonction lui-même dans une instruction using
.
Lorsque SomeType implémente IDisposable.
C'est un indice pour vous, le développeur, que SomeType utilise des ressources non gérées qui doivent être nettoyées.
Exemple:
using(SqlConnection MyConnection = new SqlConnection("Connection string"))
{
MyConnection.Open();
//...
// 1. SQLConnection is a type that implements IDisposable
// 2. So you can use MyConnection in a using statement
// 3. When using block finishes, it calls Dispose method of
// SqlConnection class
// 4. In this case, it will probably close the connection to
// the database and dispose MyConnection object
}
Vous pouvez créer vos propres objets qui implémentent IDisposable:
public class MyOwnObjectThatImplementsIDisposable : IDisposable
{
//... some code
public void Dispose()
{
// Put here the code you want to be executed when the
// using statement finish.
}
}
Vous pouvez donc utiliser un objet de type MyOwnObjectThanImplementsIDisposable dans une instruction using:
using(MyOwnObjectThatImplementsIDisposable MyObject = new MyOwnObjectThatImplementsIDisposable)
{
// When the statement finishes, it calls the
// code you´ve writed in Dispose method
// of MyOwnObjectThatImplementsIDisposable class
}
J'espère que cela t'aides
Dans ce contexte, l'instruction using
est pratique pour les types qui implémentent IDisposable. Lorsque le bloc de code quitte la portée de l'instruction using
, Dispose()
est appelée implicitement. C'est une bonne habitude lorsque vous travaillez avec des objets que vous souhaitez jeter immédiatement après utilisation.
Une instance spécifique dans laquelle vous devez être prudent en utilisant un bloc using
est avec un client de service WCF .
Comme indiqué dans cet article MSDN , encapsuler un client WCF (qui implémente IDisposable
) dans un bloc using
peut masquer toute erreur entraînant le maintien du client dans un état défectueux (comme un délai d'attente ou un problème de communication). Pour faire court, lorsque Dispose()
est appelée, la méthode Close()
du client se déclenche, mais génère des erreurs car elle est dans un état défectueux. L'exception d'origine est ensuite masquée par la deuxième exception. Pas bon.
Il existe différentes solutions de contournement, dont une dans l'article MSDN lui-même. D'autres peuvent être trouvés à IServiceOriented et blog.davidbarret.net .
Moi, je préfère la dernière méthode.
Si vous voulez une règle récapitulative. Chaque fois qu'un objet utilisant IDisposable où vous n'auriez pas de prise, utilisez l'aide. En utilisant, essentiellement, ce modèle:
try
{
//instantiate and use object
}
finally
{
//dispose object
}
Si vous n'avez pas besoin d'une capture, l'utilisation peut vous éviter de taper, ce qui est une bonne chose.
Il convient peut-être de mentionner que la raison sous-jacente de l'ajout de "utilisation" de la langue C # est la suivante: certaines ressources peuvent être suffisamment rares pour qu'il ne soit pas logique d'attendre que GC appelle IDisposable. Par exemple, les connexions DB. Si vous utilisez try/catch/enfin, vous ne vous retrouverez pas avec une connexion pendante, mais la connexion restera suspendue jusqu'à ce que GC ne démarre pas et cela peut prendre un certain temps (si vous ne la fermez pas explicitement). SI vous utilisez "using" (excusez le jeu de mots), vous libérerez la connexion immédiatement même si vous avez oublié de la fermer et même si une exception s'est produite à l'intérieur du bloc using.
Une autre raison, comme le mentionne le post précédent, est que les programmeurs n'utilisent pas toujours finalement pour nettoyer. Si vous n'utilisez finalement pas en cas d'exception vous vous retrouvez avec des ressources qui fuient…
La règle principale est: * Utilisez l'instruction USING lorsque les objets implémentent une interface IDisposable.
Cette interface fournit la méthode Dispose, qui devrait libérer les ressources de l'objet. Si cette méthode n'est pas invoquée, l'objet restera en mémoire aussi longtemps que CLR souhaite effectuer un garbage collection. Si le programmeur utilise l'instruction USING, à la fin, l'objet sera supprimé et toutes les ressources seront libres.
Il est très important que toutes les ressources qui ne sont plus utilisées soient gratuites dès que possible.
Pour plus d'informations à ce sujet, visitez ce lien: Microsoft
J'ajouterais également que l'utilisation d'une instruction using()
si quelque chose implémente IDispose
et aussi si ce que vous voulez supprimer se conserve sur des ressources NON GÉRÉES comme les connexions à la base de données et les descripteurs de fichiers.
Si c'est un objet normal avec disons un List<T>
, où T est comme un objet Customer
contenant des noms et des adresses, vous n'avez pas besoin de le faire. Le garbage collector est suffisamment intelligent pour gérer cela pour vous. Mais le garbage collector ne retournera PAS les connexions au pool de connexions ni ne fermera les descripteurs de fichiers.
Une situation est lorsque vous voulez faire quelque chose au début d'un bloc de code, puis l'annuler à la fin du bloc, sans condition (même s'il y a un lancer).
Le ctor de la classe jetable que vous générez (et appelez à l'aide de) exécuterait l'action, puis la méthode Dispose annulerait cette action. C'est généralement ainsi que je l'utilise.
D'autres personnes ont déjà évoqué "IDisposable".
Mais l'une des mises en garde lors de l'utilisation de l'instruction "using" est que, toutes les exceptions levées dans "using" ne seront pas détectées même si "SomeType" sera supprimé de toute façon.
Ainsi, dans l'extrait de code suivant,
using (SomeType t = new SomeType()){
throw new Exception("thrown within using");
}
throw new Exception("thrown within using");
ne doit pas être ignoré.