IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

IDisposable, using et brasse coulée


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut IDisposable, using et brasse coulée
    Bonjour,

    Il y a quelques temps, je me suis penché sur l'interface IDisposable et ce qu'apportaient la méthode "Dispose()" par rapport au simple destructeur.

    A ce moment, j'ai lu qu'il (de mémoire, sur la documentation MSDN) qu'il était une bonne pratique d'utiliser "using" le plus souvent possible lorsqu'on instancie une classe IDisposable afin de permettre au garbage collector de libérer au plus tôt les ressources.

    Par exemple, si j'utilise une connexion à une base de données pour rechercher des données, puis les afficher :
    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    using (SqlConnection cnx = new SqlConnection())
    {
         // lecture des données
         cnx.Close();
    }
     
    // Affichage des données

    J'ai donc pris pour habitude, dès que je bosse avec une base de données ou des fichiers par exemple, d'opter pour cette structure de code.
    Le "using" étant effectivement la plupart du temps superflu dans la mesure où la méthode encapsulante fait généralement pas grand chose d'autre, donc c'est pinailler pour disposer l'objet quelques millisecondes plus tôt tout au plus.

    Et hier, alors que j'écrivais un Web Service WCF, mon Visual Studio s'est mis à déconner (impossible de générer la solution ni lancer un debug) et je ne pouvais plus que "Analyser le code". Ce que j'ai fais.

    Et là, sur tous mes "using", il s'est mis à gueuler comme quoi je disposais plusieurs fois de suite mon objet et que donc je risquais d'avoir des erreurs de "ObjectDisposedException" ou un truc du genre.

    Du coup, j'y comprends plus rien... une âme charitable voudrait-elle bien rallumer un phare dans le brouillard de ma tête ?

  2. #2
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2005
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2005
    Messages : 562
    Par défaut
    Bonjour,

    Si, le using est toujours utile, dans le sens ou sans lui tu ne disposerais pas les ressources à tous les coups. Le using est un sucre syntaxique qui permet de ne pas écrire la suite try/catch/finally avec le dispose dans le finally afin d'être sur que tout soit disposé malgré d'éventuelles exceptions, donc c'est soit un using soit un bloc try/catch/finally.

    Donc oui si tu as un using sur tes ressources pas besoin d'avoir de dispose sur ces mêmes ressources, sans doute ce qui a provoqué ces exceptions.

    Après je vois pas trop comment t'éclairer plus, parce-que ce que je te dis n'est rien d'autre que la doc, si tu as encore tes exceptions donne un bout de code pour mieux comprendre.

    J@ck.

  3. #3
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Ok.

    Donc soit :
    - SqlConnection.Close() fait un Dispose() implicite (ce qui ne serait pas forcément délirant si le Open() est capable de réouvrir les ressources si elles ont été disposées)
    - Visual Studio part en live complet (ce qui ne m'étonnerait pas plus que ça dans la mesure où j'ai pas mal de souci avec des versions de framework différentes d'un PC à l'autre alors que je bosse sur les mêmes sources)

    Sinon, je n'ai pas eu d'erreur. C'est juste l'analyseur de code qui m'a mis en garde.
    Du coup j'ai viré tous mes using.

    Si je ne m'abuse, du moment qu'on sort du scope de l'instance de l'objet disposable, de toute façon le Dispose() est déclenché :

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void MaMethode()
    {
        SqlConnection cnx = new SqlConnection();
        cnx.Open();
        Console.Write("Connection ouverte");
        cnx.Close();
    }

    Revient exactement au même que : (du moment qu'il n'y a rien de plus dans la méthode)

    Code csharp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void MaMethode()
    {
        using (SqlConnection cnx = new SqlConnection())
        {
            cnx.Open();
            Console.Write("Connection ouverte");
            cnx.Close();
        }
    }

    Au détail près que dans le deuxième cas, peut-être que le programme est tenté de disposer deux fois la connexion, si le GC n'a pas eu le temps de le faire entre la sortie du using et la sortie de la métode ?

  4. #4
    Membre émérite
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2005
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Distribution

    Informations forums :
    Inscription : Juillet 2005
    Messages : 562
    Par défaut
    Alors justement non, les deux bout de codes ne sont pas identique, si dans le premier extrait, tu as une exception qui est levée sur cnx.Open();, ce qui est parfaitement possible, alors tu ne disposera pas cnx car tu n'arrivera jamais au Close().

    Je crois que oui le Close() fait un dispose implicite, cas qu'il marque la ressources comme étant à disposer mais ne le fait pas forcément immédiatement, ainsi si dans un futur proche le GC se lance alors il en profitera pour disposer.

    Cependant je comprends pas pourquoi tu aurais des avertissements sur le deuxième bout de code. J'aurais écris la même chose ... Erreur ou avertissement normalement tu dois avoir un code style CS1061 ou CA1033, au pire donne le nous.

    J@ck.

  5. #5
    Membre éclairé
    Homme Profil pro
    Ingénieur .Net
    Inscrit en
    Décembre 2014
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur .Net
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2014
    Messages : 71
    Par défaut
    Si tu utilise un using avec un SqlConnection, le close est implicitement appelé.

    The following example creates a T:System.Data.SqlClient.SqlConnection, opens it, displays some of its properties. The connection is automatically closed at the end of the using block.
    Source

  6. #6
    Expert confirmé

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Alors pour bien comprendre le using, il faut savoir que :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    using(var x = new SqlConnection())
    {
       // ...
    }
    est strictement équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    var x = new SqlConnection()
    try
    {
       // ...
    }
    finally
    {
       if (x != null)
       {
          x.Dispose();
       }
    }
    Citation Envoyé par J@ckHerror
    Je crois que oui le Close() fait un dispose implicite
    Absolument pas ! C'est même le contraire ! C'est l'appel à Dispose() qui fait appel à Close()
    Citation Envoyé par StringBuilder
    Sinon, je n'ai pas eu d'erreur. C'est juste l'analyseur de code qui m'a mis en garde.
    Du coup j'ai viré tous mes using.

    Si je ne m'abuse, du moment qu'on sort du scope de l'instance de l'objet disposable, de toute façon le Dispose() est déclenché :
    Attention tout de même. Avec le using, la méthode Dispose() est appelée à la sortie du bloc using. Sans le using, la méthode Dispose() sera appelée... lors de la mise en oeuvre du ramasse-miette (et encore, pas forcément au prochain déclenchement !), et à condition que l'instance correspondante ne soit plus référencée.

    A noter également qu'il est, si l'implémentation est correct, tout à fait sûr d'appeler la méthode Dispose sur un objet déja disposé (l'interface IDisposable définit ce comportement comme étant le bon).
    Toujours si l'implémentation est correct, l'appel d'une méthode autre que Dispose() doit générer une exception ObjectDisposedException
    Citation Envoyé par StringBuilder
    Donc soit :
    - SqlConnection.Close() fait un Dispose() implicite (ce qui ne serait pas forcément délirant si le Open() est capable de réouvrir les ressources si elles ont été disposées)
    - Visual Studio part en live complet (ce qui ne m'étonnerait pas plus que ça dans la mesure où j'ai pas mal de souci avec des versions de framework différentes d'un PC à l'autre alors que je bosse sur les mêmes sources)
    SqlConnection.Close() ne fait pas de Dispose() implicite. En théorie, un objet disposé ne devrait plus être utilisable. Pour faire une analogie avec le C++, c'est comme si on avait un pointeur sur lequel on a fait un delete : le pointeur n'est plus utilisable. La méthode Dispose() permet de libérer les ressources autres que la mémoire (par exemple, une connexion à une base de données) de manière temporellement déterministe.

    Ici, j'ai plutôt l'impression que c'est ton Visual Studio qui part en cacahuète !

Discussions similaires

  1. [Débutant] Conversion de "using" en IDisposable
    Par kryptong dans le forum Développement Web avec .NET
    Réponses: 2
    Dernier message: 10/07/2013, 16h43
  2. Erreur de compilation après modification du Uses
    Par DevelOpeR13 dans le forum Langage
    Réponses: 5
    Dernier message: 30/10/2007, 14h23
  3. [web] use CGI.pm
    Par martijan dans le forum Web
    Réponses: 18
    Dernier message: 09/09/2003, 14h11
  4. "use may clash"
    Par Jibees dans le forum Modules
    Réponses: 4
    Dernier message: 15/05/2003, 16h27
  5. Connaitre l'unitée à ajouter dans USES
    Par DelphiCool dans le forum Langage
    Réponses: 7
    Dernier message: 01/08/2002, 13h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo