Je vais me permettre un peu d'histoire pour tenter de clarifier l'usage du using. En C++ l'acquisition et la libération des ressources sont toutes deux déterministes ; la mémoire est une ressources, mais les fichiers, connexions réseau, connexions aux périphériques, etc... en sont aussi.
Le mot clé new va :
- réserver un espace mémoire sur le tas et retourner l'adresse ;
- appeler le constructeur spécifié.
Le mot clé delete lui va :
- appeler le destructeur (avec quelques subtilités concernant le polymorphisme), dont la tâche sera de libérer les ressources réquisitionnées par l'objet au cours de sont cycle de vie ;
- libérer la mémoire dédiée à l'objet.
On détruit un objet à la demande et on est alors toujours certain que les ressources sont immédiatement libérées.
La gestion de la mémoire étant un processus complexe, récurrent et sujet à erreur, on a créé des langages dont la gestion de la mémoire sera automatisé, ce qui est le rôle du garbage collector en C#. Ceci a créé une dissociation entre la gestion de la mémoire (automatique) et la gestion des autres ressources (manuelle). D'ailleurs les classes C# n'ont pas un destructeur mais un finaliseur. Lorsqu'un objet n'est plus utile et qu'il n'y a plus de référence, le garbage collector pourra s'en débarrasser à sa discrétion et pas forcément aussi vite qu'on le voudrait. La libération des ressources est devenu aléatoire ; ce n'est pas un problème pour ce qui est de la mémoire dont la gestion est déléguée au garbage collector, mais c'en est un pour les ressources que l'on gère nous-même. La réponse à ce problème est le concept des objets IDisposable : ce sont des objets dont on souhaite pouvoir libérer volontairement les ressources.
On retombe alors sur un problème classique du C++ : la libération des ressources en cas d'exception. L'utilisation habituelle des IDisposable se fait donc dans le contexte d'un try/finally (le code du finally est toujours appelé après le try ou un éventuel catch, qu'il y ait eu ou pas d'exception). Le reste a déjà été mentionné par les autres intervenants, le mot clé using permet de simplifier le code, d'autant qu'on peut les imbriquer :
1 2 3 4 5
| using (var connection = MachinTrucConnection.Open())
using (var session = connection.OpenSession())
{
// code
} |
En général un IDisposable va disposer par lui-même des objets IDisposable qu'il a utilisé :
using(var reader = new StreamReader(File.OpenRead("monfichier.txt")) { ... }
La méthode statique OpenRead de la classe File renvoie un FileStream (IDisposable).
Partager