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 :

Délégué : qu'est-ce qui a bien pu se passer ?


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre émérite
    Profil pro
    Développeur Web
    Inscrit en
    Février 2008
    Messages
    2 896
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2008
    Messages : 2 896
    Par défaut Délégué : qu'est-ce qui a bien pu se passer ?
    Bonjour tout le monde,

    Pour tester des délégués, j'ai créé une classe qui reçoit le chemin d'un fichier dans son constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
        public class Class1
        {
    		StreamWriter F;
     
    		public Class1(string path)
    		{
    			this.F = new StreamWriter(path);
    		}
          ...
    Donc bien sûr, pour que le fichier soit fermé en fin d'usage, j'ai mis ça dans le destructeur de la classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    		~Class1()
    		{
    			F.Close();
    		}
    Or voilà-t-y pas qu'au premier appel on me dit pas moyen, le fichier est déjà fermé.
    Ah bon, l'objet aurait donc été détruit avant la fin de mon programme, sans que je demande rien explicitement ?

    Bizarre, mais admettons. J'enlève le destructeur.

    Ouais, ben mauvaise idée : mon fichier reste vide, je teste six fois d'affilée, je ne comprends pas. Et puis je remets mon code de constructeur, et là ça marche.

    Je ne serais pas plus surpris que ça que ça reste mystérieux ?

  2. #2
    Membre Expert
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    Va falloir donner des précisions parce que :
    • Y'a pas de délégué dans le code fourni
    • Dans 99% des cas on n'écrit pas de destructeur en C# (je suppose donc que tu viens du C++ et tiens à préciser que tenter d'appliquer les principes d'un langage à un autre c'est souvent pas la bonne approche) parce que contrairement au C++ un destructeur en C# n'est pas déterministe.
    • Il faudrait le code qui utilise cette classe pour tenter de comprendre ce qu'il se produit
    • StreamWriter implémente IDisposable (qui possède une méthode Dispose ; qui elle sert à la destruction déterministe) et une classe qui possède un membre implémentant IDisposable doit également implémenter cette interface pour fournir la méthode Dispose et ainsi assurer une destruction déterministe de son membre sous-jacent
      Plus simplement, StreamWriter implémente IDisposable et est membre de ta classe => ta classe doit implémenter IDisposable

  3. #3
    Membre émérite
    Profil pro
    Développeur Web
    Inscrit en
    Février 2008
    Messages
    2 896
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2008
    Messages : 2 896
    Par défaut
    Bon, ben ... OK.

    C'est bien parce que je viens de C# que j'ai pensé à mettre le destructeur, autrement j'aurais été jusqu'à demain à me demander pourquoi mon fichier était vide ...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
     
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
     
    namespace ClassLibrary1
    {
        public class Class1
        {
    		StreamWriter F;
     
    		public Class1(string path)
    		{
    			this.F = new StreamWriter(path);
    		}
     
     
    		public void Log1(string str1, string str2)
    		{
    			int ttl = str1.Length + str2.Length + 3;
    			Console.WriteLine("".PadLeft(ttl, '-'));
    			Console.WriteLine(str2 + " : " + str1);
    			Console.WriteLine("".PadLeft(ttl, '-'));
    		}
     
    		public void log2(string str1, string str2)
    		{
    			int ttl = str1.Length + str2.Length + 3;
    			Console.WriteLine("".PadLeft(ttl, '='));
    			Console.WriteLine(str2 + " : " + str1);
    			Console.WriteLine("".PadLeft(ttl, '='));
    		}
     
    		public void log3(string str1, string str2)
    		{
    			F.WriteLine(str2 + " : " + str1);
    		}
     
    		public void log4(string str1, string str2)
    		{
    			String strDate = System.DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss >");
    			F.WriteLine(strDate + str2 + " : " + str1);
    		}
     
    		~Class1()
    		{
    			F.Close();
    		}
    	}
    }
    Ah oui et puis on avait dit la classe appelante, aussi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    namespace ConsTestLog01
    {
    	public delegate void Dlog(string str1, string str2);
    	class Program
    	{
     
    		static void Main(string[] args)
    		{
    			string pathModule = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
     
    			ClassLibrary1.Class1 class1 = new ClassLibrary1.Class1(System.IO.Path.Combine(pathModule, "log.txt"));
     
    			Dlog logo = new Dlog(class1.Log1);
    			logo += class1.log2;
     
    			logo("Texte 1", "Titre 1");
    			Console.ReadKey();
     
    			logo -= class1.Log1;
    			logo("Autre", "Test");
     
    			Console.ReadKey();
     
    			logo += class1.log4;
     
    			logo("Le travail", "Et voilà");
     
    			Console.ReadKey();
    		}
    	}

  4. #4
    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
    Citation Envoyé par Sehnsucht Voir le message
    parce que contrairement au C++ un destructeur en C# n'est pas déterministe.
    Juste une précision : c'est l'appel au destructeur qui n'est pas déterministe. Le destructeur en lui-même l'est

    Citation Envoyé par Sehnsucht
    Tout ce qui concerne les destructeurs/finaliseurs (déjà les mots et les concepts sont inversés en C#)
    Rien n'est inversé. C# n'a pas de notion de finaliseur. Il n'existe que la notion de destructeur. Le destructeur ne fait que redéfinir la méthode Finalize() d'une classe, tout en gérant l'appel hiérarchique de la méthode Finalize() de la classe mère s'il y en a une.

    Citation Envoyé par Sehnsucht
    Même si c'est très improbable, le langage n'interdit pas à un objet d'être détruit sur le thread du finaliseur pendant la construction de l'objet sur le thread principal par exemple.
    Euh non. C'est juste impossible. Et encore heureux ! Bonjour les effets de bords complètement imprévisibles sinon !

    Pour le fonctionnement du ramasse-miettes et la notion de destructeur en C#, je vous invite à lire l'article que j'ai écris à ce sujet.

    Citation Envoyé par Sehnsuch
    il suffit du bon membre dans la classe pour que ça fonctionne sans implémenter d'interface particulière [foreach par exemple])
    Encore raté. Gluups à raison : il faut que l'objet implémente l'interface IEnumerable (ou sa variante générique IEnumerable<T>).

  5. #5
    Membre Expert
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    Perso, je répète les choses que lis, surtout quand elles viennent d'Eric Lippert et de Jon Skeet ; j'ai tendance à me dire qu'ils ont raison.

    Citation Envoyé par François DORIN Voir le message
    Rien n'est inversé. C# n'a pas de notion de finaliseur.
    https://blogs.msdn.microsoft.com/eri...d-a-finalizer/
    What’s the difference, if any, between a “destructor” and a “finalizer”?
    Both are mechanisms for cleaning up a resource when it is no longer in use. When I was asked this, at first I didn’t think there was a difference. But some Wikipedia searches turned up a difference; the term “destructor” is typically used to mean a deterministically-invoked cleanup, whereas a “finalizer” runs when the garbage collector says to run it.

    Doesn’t that mean that the C# spec uses the term “destructor” incorrectly?
    Yes, by these definitions, the C# spec gets it wrong. What we call a “destructor” in the spec is actually a finalizer, and what we call the “Dispose()” method invoked by a “using” statement is in fact a “destructor”.
    Citation Envoyé par François DORIN Voir le message
    Euh non. C'est juste impossible. Et encore heureux ! Bonjour les effets de bords complètement imprévisibles sinon !
    https://ericlippert.com/2013/06/10/c...n-destruction/
    It is possible for an object to be destructed on the finalizer thread while its constructor is running in a user thread!
    Citation Envoyé par François DORIN Voir le message
    Encore raté. Gluups à raison : il faut que l'objet implémente l'interface IEnumerable (ou sa variante générique IEnumerable<T>).
    https://blogs.msdn.microsoft.com/eri...g-the-pattern/
    https://stackoverflow.com/a/6369023
    You might think that in order to use a foreach loop, the collection you are iterating over must implement IEnumerable or IEnumerable<T>. But as it turns out, that is not actually a requirement. What is required is that the type of the collection must have a public method called GetEnumerator, and that must return some type that has a public property getter called Current and a public method MoveNext that returns a bool.
    Exemple : ce code fonctionne parfaitement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    class Foo{
        public Foonumator GetEnumerator ()
        {
            return new Foonumator ();
        }
    }
     
     
    class Foonumator
    {
        int counter = 0;
     
        public int Current { get { return 42; } }
        public bool MoveNext () { return counter++ < 10; }
    }
     
     
    public class Program
    {
        public static void Main ()
        {
            foreach (var n in new Foo ())
            {
                System.Console.WriteLine (n);
            }
        }
    }

  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
    Bon, de petites disgressions, mais c'est intéressant

    Citation Envoyé par Sehnsucht Voir le message
    What’s the difference, if any, between a “destructor” and a “finalizer”?
    Both are mechanisms for cleaning up a resource when it is no longer in use. When I was asked this, at first I didn’t think there was a difference. But some Wikipedia searches turned up a difference; the term “destructor” is typically used to mean a deterministically-invoked cleanup, whereas a “finalizer” runs when the garbage collector says to run it.

    Doesn’t that mean that the C# spec uses the term “destructor” incorrectly?
    Yes, by these definitions, the C# spec gets it wrong. What we call a “destructor” in the spec is actually a finalizer, and what we call the “Dispose()” method invoked by a “using” statement is in fact a “destructor”.
    D'accord, je comprends mieux notre incompréhension. Je prenais le finaliseur comme la méthode Finalize() dont dispose tout objet. Méthode, qui, en C#, n'est pas appelable ni redéfinissable*. Je réagissais sur une inversion destructeur/finaliseur en C#, qui n'a pas de sens avec cette définition. Si on prend la définition Wikipédia, effectivement il y a une inversion.

    Là où c'est drôle, c'est que le CLR ne définit pas la notion de destructeur, juste celle de finaliseur. C# ne contient que la notion de destructeur, et pas de finaliseur.


    * il est possible de définir une méthode Finalize() en C#. On a le droit à un avertissement du compilateur. Par contre, on ne peut pas définir à la fois un destructeur et la méthode Finalize(). Mais si on redéfinie la méthode Finalize, à ce moment alors, elle sera appelable. Mais uniquement dans ce cas là.


    Citation Envoyé par Sehnsucht Voir le message
    It is possible for an object to be destructed on the finalizer thread while its constructor is running in a user thread!
    Difficile à croire que cela soit effectivement le cas. L'instruction CIL pour la création d'un objet est newobj, qui place l'objet créé sur la pile. Dès lors, tant que l'on n'est pas sorti du constructeur, l'objet est référé car il est sur la pile. Je ne vois pas comment il peut être marqué comme collectable durant l'appel au constructeur. Et toutes les optimisations du monde utilisent newobj pour la création d'un objet. Donc bon...

    Par contre, il peut effectivement y avoir de sacrer effet de bord non prévu, comme le finaliseur qui est appelé immédiatement après la création de l'objet (et encore, il faut une sacrée pression sur la mémoire, car il faudrait plusieurs déclenchement du ramasse-miettes !

    Le plus connu des effets de bord, et le plus perturbant sans doute, est celui concernant les timer, où le code fonctionne parfaitement en mode debug, mais pas en mode release (justement à cause d'optimisations).

    Citation Envoyé par Sehnsuch
    Exemple : ce code fonctionne parfaitement
    Merci. Je me coucherai moins bête ce soir ! Le pire, c'est que c'est largement marqué dans la MSDN...

  7. #7
    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
    Je m'avoue vaincu. J'ai réussi à faire un exemple où le destructeur est appelé dans le constructeur :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    using System;
    using System.Threading;
     
    namespace TestConstructeur
    {
        public class Program
        {
            public Program()
            {
                GC.Collect();
                Thread.Sleep(100);
                Console.WriteLine("Constructeur");
            }
     
            ~Program()
            {
                Console.WriteLine("Kill !");
            }
     
            public void SayHello()
            {
                Console.WriteLine("Hello World");
            }
     
            public static void Main()
            {
                Program p = new Program();
                p.SayHello();
                Console.ReadLine();
            }
     
        }
    }
    A exécuter en mode release sans déboguage.

    Après, est-ce réellement gênant ? Non. Si le JIT autorise cela, c'est qu'il a bien détecter que cela ne posait pas de soucis. C'est contre intuitif, mais il est vrai que l'appel du finaliseur est non-déterministe. Et si l'objet peut être collecté, alors autant le faire.

    Le reste des appels est conforme à ce qui est attendu (ouf !). Intuitivement, on pourrait s'attendre à ce que le destructeur ne soit appeler qu'après la dernière méthode, sans savoir quand exactement. Il s'avère que non. Mais le destructeur ne sera appelé que lorsque l'objet ne sera plus utile (et encore heureux !).

    Et je viens de me renseigner un peu sur le pourquoi cette situation est possible. L'instruction newobj étant sensée mettre la référence sur la pile, la référence ne devrait pas être collectable. En fait, l'instruction ne le fait qu'une fois le constructeur appelé. Pas avant. Donc je penche ici pour une optimisation poussée du JIT (le compilateur ne peut pas vraiment intervenir ici) qui détecte que l'objet derrière ne sera plus du tout utilisé (possible si les appels successifs sont inlinés).

    D'ailleurs, si on remplace la méthode SayHello par
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
      public void SayHello()
            {
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
                Console.WriteLine("Hello World");
            }

    on constate que le destructeur n'est plus appelé. Pourquoi ? Avec ce nouveau code, la taille de la méthode dépasse la taille permettant au JIT d'inliné la méthode. Le JIT n'est alors plus en mesure de savoir si la référence sera utilisée ou pas et donc ne peut pas la libérer.

    Le seul cas véritablement problématique et où il faudrait aider le ramasse-miettes, c'est en cas d'interaction avec du code natif.

    Mais je pense que ça va faire l'objet d'un petit billet de blog ça

  8. #8
    Max
    Max est déconnecté
    Expert confirmé

    Avatar de Max
    Homme Profil pro
    Artisan développeur
    Inscrit en
    Mai 2007
    Messages
    2 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Artisan développeur
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2007
    Messages : 2 954
    Par défaut
    Le choc des titans

  9. #9
    Membre Expert
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    Bah autant sur les histoire de destructeur et tout je me serais pas avancé trop parce que c'est au delà de mes connaissances (au passage pour d'autres infos concernant les finaliseurs il y a ces 2 articles (partie 1, partie 2) qui sont intéressants ; toujours d'Eric Lippert, de toute façon tout ce que lui ou Jon Skeet écrivent se révèlent rarement être des pertes de temps),
    autant concernant le foreach et cette capacité de "duck typing" (à défaut d'un meilleur terme) là j'étais sur de mon coup ; vu que ça s'applique aussi aux méthodes associées au mot clef de Linq (select where etc.) où il suffit de la bonne méthode avec la signature appropriée (chose que j'ai pas mal explorée à titre perso) ; mais je digresse aussi là, on s'éloigne du sujet initial ^^

  10. #10
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 199
    Par défaut
    Citation Envoyé par Gluups Voir le message
    Je ne serais pas plus surpris que ça que ça reste mystérieux
    s'il y a du mystère il vient de ta compréhension du code, c# n'improvise pas

    je plussoie légèrement pour le IDisposable (légèrement car ca semble bizarre d'ouvrir un fichier dans un constructeur et de le fermer plus tard, normalement on l'ouvre juste avant d'écrire et on le ferme dans la foulée, même avec un pattern Builder ca passe)

    le destructeur en c# est appelé au moment de la libération de la mémoire, et on ne sait donc pas trop quand (après la non utilisation de l'instance certes mais ca peut etre beaucoup plus tard)
    de plus le destructeur est souvent implémenté en parallèle de IDisposable car si on a de la mémoire externe à libérer (oui car c'est fait pour libérer de la mémoire, pas fermer un fichier) on préfère le faire rapidement.
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Membre Expert
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    Tout ce qui concerne les destructeurs/finaliseurs (déjà les mots et les concepts sont inversés en C#), IDisposable moins, encore que c'est lié ; c'est super casse-gueule.
    Même si c'est très improbable, le langage n'interdit pas à un objet d'être détruit sur le thread du finaliseur pendant la construction de l'objet sur le thread principal par exemple.

  12. #12
    Membre émérite
    Profil pro
    Développeur Web
    Inscrit en
    Février 2008
    Messages
    2 896
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2008
    Messages : 2 896
    Par défaut
    OK ça devient plus clair, c'est vrai que j'étais un peu flou sur la distinction entre les deux.

    Alors la classe de log se finit par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    		public void Dispose()
    		{
    			F.Close();
    		}
     
    		~Class1()
    		{
     
    		}

    et du coup dans la classe appelante il faut bien penser à ajouter


  13. #13
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 199
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 199
    Par défaut
    un finaliseur vide ne sert pas, supprime le

    pour penser à appeler dispose (et surtout pour s'assurer que c'est fait) il y a le bloc using

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    using (var a = new quelquechoseIDisposable())
    {
       // code
    }  // ici a.Dispose() est appelé
    ceci correspond à un try/finally, donc même en cas d'exception Dispose est appelé
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  14. #14
    Membre Expert
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Par défaut
    Au cas où ça serait pas clair pour utiliser un bloc using ; il faut que la classe implémente IDisposable ; suffit pas d'avoir une méthode Dispose dans la classe ; ça semble couler de source mais on sait jamais (surtout que y'a d'autres choses où il suffit du bon membre dans la classe pour que ça fonctionne sans implémenter d'interface particulière [foreach par exemple])

  15. #15
    Membre émérite
    Profil pro
    Développeur Web
    Inscrit en
    Février 2008
    Messages
    2 896
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Février 2008
    Messages : 2 896
    Par défaut
    Citation Envoyé par Sehnsucht Voir le message
    (surtout que y'a d'autres choses où il suffit du bon membre dans la classe pour que ça fonctionne sans implémenter d'interface particulière [foreach] par exemple])
    Là c'est plutôt IEnumerable, pas vrai ?

Discussions similaires

  1. Qu'est ce qui ne va pas dans ma requête ???
    Par Higestromm dans le forum Langage SQL
    Réponses: 3
    Dernier message: 03/09/2018, 21h50
  2. Qu'est-ce qui marche bien en 2018?
    Par Sotux dans le forum Emploi
    Réponses: 17
    Dernier message: 31/08/2018, 16h12
  3. qu'est ce qui va pas dans cette fonction???
    Par access001 dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 18/04/2006, 13h10
  4. qu'est-ce qui cloche dans ma requete?
    Par a-chan dans le forum Langage SQL
    Réponses: 4
    Dernier message: 20/06/2005, 09h02
  5. Réponses: 1
    Dernier message: 21/02/2005, 12h40

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