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 :

Class static = instance unique ?


Sujet :

C#

  1. #21
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Citation Envoyé par maa Voir le message
    Donc instance unique ou pas d'instance après compilation ?
    Pas d'instance. Juste une notation qui explicite bien que la classe ne peut être instanciée, ne comporte que des membres statiques, et dont un bout de code se déclenchera avant tout appel à un de ses membres : le constructeur.
    ಠ_ಠ

  2. #22
    maa
    maa est déconnecté
    Membre actif
    Avatar de maa
    Inscrit en
    Octobre 2005
    Messages
    672
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2005
    Messages : 672
    Points : 288
    Points
    288
    Par défaut
    Ok pour nous pas d'instance, mais est ce que au niveau de l'IL une instance est réellement crée ?
    ****************************************

    - I don’t write plumbing code anymore
    - I use PostSharp
    - And you?


    ****************************************

  3. #23
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    Citation Envoyé par tomlev Voir le message
    En fait une classe statique est plus ou moins équivalente au concept de Module en VB... d'ailleurs je ne sais pas si ça existe encore en VB.NET ?
    +1
    Oui ça existe toujours en VB.NET. .... Malheureusement.

    Citation Envoyé par maa Voir le message
    Ok pour nous pas d'instance, mais est ce que au niveau de l'IL une instance est réellement crée ?
    Pas d'instance à ma connaissance.

    Citation Envoyé par Keihilin Voir le message
    "L'inlining" est une optimisation utilisée par le compilateur.

    Pour résumer on peut dire que l'inlining, c'est le remplacement d'un appel de fonction par une copie de son corps.

    Les avantages sont nombreux, les surcoûts de l'appel sont évités : les instructions call et return, la sauvegardes des registres, le passage de paramètres et l'ajustement de la pile n'ont plus lieu d'être.

    Il convient par contre de trouver un juste milieu car la forte expansion du code peut conduire à une dégradation des performances.
    On peut agir manuellement sur le code pour dire qu'une méthode est inline ou pas? (Comme en C++). Si oui comment?
    Sinon quelles sont les autres critères qui peuvent rendre une méthode de classe inline?
    Je pensais que seul les propriétés étaient inline en .NET

  4. #24
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Salut,

    en IL non plus, il n'y a pas d'instance. De plus, il existe des instruction specifique pour les membres statiques. Un exemple 'bateau' pour comparer :

    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
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string str = "Salut !";
     
                StaticClass.Display(str);
     
                new InstanceClass().Display(str);
            }
        }
     
        public static class StaticClass
        {
            static string str;
     
            public static void Display(string s)
            {
                str = s;
                Console.WriteLine(str);
            }
        }
     
        public class InstanceClass
        {
            string str;
     
            public void Display(string s)
            {
                str = s;
                Console.WriteLine(str);
            }
        }
     
     
    }
    Donc en gros deux classes faisant la meme chose, la premiere statiquement, l'autre etant un objet. En IL, le Main nous donnera ceci :

    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
    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 2
        .locals init (
            [0] string str)
        L_0000: nop 
        L_0001: ldstr "Salut !"
        L_0006: stloc.0 
        L_0007: ldloc.0 
        L_0008: call void ConsoleApplication1.StaticClass::Display(string)
        L_000d: nop 
        L_000e: newobj instance void ConsoleApplication1.InstanceClass::.ctor()
        L_0013: ldloc.0 
        L_0014: call instance void ConsoleApplication1.InstanceClass::Display(string)
        L_0019: nop 
        L_001a: ret 
    }
    On voit bien que dans le cas static, il n'y aucune creation d'instance, et que l'on appelle directement la methode Display. Dans le second, il y a d'abord un newobj puis l'appel concret. Dans le corps du Display Static, on trouve :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .method public hidebysig static void Display(string s) cil managed
    {
        .maxstack 8
        L_0000: nop 
        L_0001: ldarg.0 
        L_0002: stsfld string ConsoleApplication1.StaticClass::str
        L_0007: ldsfld string ConsoleApplication1.StaticClass::str
        L_000c: call void [mscorlib]System.Console::WriteLine(string)
        L_0011: nop 
        L_0012: ret 
    }
    En fait, les instructions stsfld et ldsfld sont des instructions specialisées dans la manipulation des champs statiques. Donc ici, on enregistre le premier argument dans le champs static str (ldarg.0 et stsfld) puis on passe le champ static sur le stack (ldsfld) et on l'affiche par un CW (call ...).

    Pour la methode d'instance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .method public hidebysig instance void Display(string s) cil managed
    {
        .maxstack 8
        L_0000: nop 
        L_0001: ldarg.0 
        L_0002: ldarg.1 
        L_0003: stfld string ConsoleApplication1.InstanceClass::str
        L_0008: ldarg.0 
        L_0009: ldfld string ConsoleApplication1.InstanceClass::str
        L_000e: call void [mscorlib]System.Console::WriteLine(string)
        L_0013: nop 
        L_0014: ret 
    }
    c'est la meme idée (les deux methodes faisant la meme chose), mais il faut jouer avec une reference supplementaire, le pointeur vers this (qui est en fait le premier argument de la methode dans les objets, ce qui explique que le premier argument d'une methode d'instance est à l'index 1 et non 0 comme precedemment). En effet les instructions stfld et ldfld attendent deux choses sur le stack, la reference vers l'objet en question (this ici) et la nouvelle valeur (pour stfld du moins).

    Enfin pour la structure des classes en langage IL, une classe static est presenté comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    .class public abstract auto ansi sealed beforefieldinit StaticClass
        extends [mscorlib]System.Object
    la classe, pour nous static, est pour le compilateur abstract et sealed (ce qui est impossible à specifier pour une classe => erreur compilateur), et de plus, le compilateur ne generera pas de constructeur par defaut, ce qu'il a fait pour la classe d'instance ci-dessus.

    En conclusion, meme en IL, avec une classe static, tu es sur qu'aucune instance de ce type ne sera jamais créé, ou utilisée en classe de base (pas de .ctor, sealed, abstract)


    Pour revenir au sujet du thread, les classes statics, je les utilise pour definir des constantes, ou pour "enfermer" des methodes p/invokées (ce que fait Microsoft dans son framework d'ailleurs pour tout les appels de ce type). Mais le probleme des classes statics, c'est que tu ne peux pas facilement controler la durée de vie de ses membres contrairement à une instance qui peut implementer IDisposable, donc j'evite de tenir des ressources qui pourrait etre amené à etre disposées ou qui auraient une durée de vie plus courte que le programme, dans des elements statics.

    Edit ; @ Abelman

    Apparement, on ne peut pas jouer par instructions pour forcer un inlining en C#, mais Microsoft donne quand meme une liste pour savoir si une methode sera inlinée :

    Methods that are greater than 32 bytes of IL will not be inlined.

    Virtual functions are not inlined.

    Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.

    Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining.

    If any of the method's formal arguments are structs, the method will not be inlined.
    NB : ca date de 2003, donc peut etre est-ce different maintenant.

  5. #25
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Moi un truc m'embête lorsque vous dites pas d'instance. Cela voudrait dire que les valeurs des variables de la classe static ne sont pas stockées en mémoire mais dans un fichier binaire et qu'on le lirait lorsque l'on veut récupérer une de ces valeurs ?
    Dans ce cas la le code serait stockées dedans également, puis au moment de l'utilisation d'une méthode, il serait lu, compilé, puis interprété ?
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  6. #26
    Inscrit

    Profil pro
    Inscrit en
    Février 2004
    Messages
    862
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : Suisse

    Informations forums :
    Inscription : Février 2004
    Messages : 862
    Points : 1 229
    Points
    1 229
    Par défaut
    Citation Envoyé par abelman Voir le message
    On peut agir manuellement sur le code pour dire qu'une méthode est inline ou pas? (Comme en C++). Si oui comment?
    Sinon quelles sont les autres critères qui peuvent rendre une méthode de classe
    Je ne pense pas que l'on puisse agir directement sur l'inlining...Le compilateur utilise une heuristique un peu complexe pour choisir les méthodes candidate à "l'inlining".

    Ce que je sais :

    • Les méthodes dont l'IL fait plus de 32 bytes ne sont pas candidates.
    • Les méthodes virtuelles ne sont pas candidates.
    • Les méthodes avec un contrôle de flux complexe ne sont pas candidates.
    • Les méthodes comportant un block de gestion d'exception ne sont pas candidates. (mais les méthodes pouvant lever une exception peuvent l'être).
    • Les méthodes ayant un struct comme paramètre ne sont pas candidates.


    Donc non, il n'y a pas que les propriétés qui sont "inlinées", mais elles sont effectivement des candidates privilègiées.

    Certains critères qui excluent "l'inlining" peuvent paraître limites, et on se dit que ça ne laisse pas beaucoup de candidats, mais il ne faut pas oublier que l'on parle d'un compilateur JIT et qu'il faut bien trouver un compromis entre sa vitesse d'exécution et les optimisation qu'il peut faire...

    Précision : j'avais cherché ces informations il y a un bon moment déjà, et du coup je certifie leur pertinence sur le fx 1.1, mais il est possible que les choses aient un peu changé sur le 2.0 et le 3.0 !
    In my experience, any attempt to make any system idiot proof will only challenge God to make a better idiot.

  7. #27
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    On voit bien que dans le cas static, il n'y aucune creation d'instance
    Euh... perso moi je vois rien du tout ! Mais merci pour ce petit cours de MSIL, ça me rappelle le bon vieux temps de l'assembleur...

    Moi un truc m'embête lorsque vous dites pas d'instance. Cela voudrait dire que les valeurs des variables de la classe static ne sont pas stockées en mémoire mais dans un fichier binaire et qu'on le lirait lorsque l'on veut récupérer une de ces valeurs ?
    Dans ce cas la le code serait stockées dedans également, puis au moment de l'utilisation d'une méthode, il serait lu, compilé, puis interprété ?
    Oula, pas du tout... les valeurs sont bien stockées en mémoire, et n'ont d'existence qu'au cours de l'éxécution du programme. D'ailleurs la portée des membres statiques d'une classe est limitée à l'application : si tu lances 2 programmes qui appellent tous les 2 Process.GetCurrentProcess() (par exemple), le résultat ne sera pas le même, heureusement !

  8. #28
    Rédacteur
    Avatar de abelman
    Inscrit en
    Février 2003
    Messages
    1 106
    Détails du profil
    Informations forums :
    Inscription : Février 2003
    Messages : 1 106
    Points : 2 629
    Points
    2 629
    Par défaut
    Merci SirJulio et Keihilin ;-)

    Citation Envoyé par ced600 Voir le message
    Moi un truc m'embête lorsque vous dites pas d'instance. Cela voudrait dire que les valeurs des variables de la classe static ne sont pas stockées en mémoire mais dans un fichier binaire et qu'on le lirait lorsque l'on veut récupérer une de ces valeurs ?
    Dans ce cas la le code serait stockées dedans également, puis au moment de l'utilisation d'une méthode, il serait lu, compilé, puis interprété ?
    Pourquoi stockées dans un fichier?
    Elles sont stockées en mémoire à une adresse qui n'est "liée" à aucune instance si je peux me permettre de parler ainsi.
    Exactement comme serait stockée une variable globale en C.

  9. #29
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Citation Envoyé par ced600 Voir le message
    Moi un truc m'embête lorsque vous dites pas d'instance. Cela voudrait dire que les valeurs des variables de la classe static ne sont pas stockées en mémoire mais dans un fichier binaire et qu'on le lirait lorsque l'on veut récupérer une de ces valeurs ?
    Dans ce cas la le code serait stockées dedans également, puis au moment de l'utilisation d'une méthode, il serait lu, compilé, puis interprété ?
    Salut,

    c'est juste que le champs, methodes ou autres n'est lié à aucune instance, mais existe dans le type en tant que tel. Comme le dirait le standard du CLI :

    Fields can be marked as static, indicating that the field is not part of values of the type but rather a location associated with the type as a whole. Locations for the static fields are created when the type is loaded and
    initialized when the type is initialized.

    Fields not marked as static define the representation of a value of a type by defining the substructure of the value (see §8.4.1). Locations for such fields are created within every value of the type whenever a new value is
    constructed. They are initialized during construction of the new value. A non-static field of a given name is always located at the same place within every value of the type.
    Si tu preferes, il existe une initialisation pour tous les types que tu utilises, et independemment de toutes creations d'instance de ce type. Donc les valeurs placées en static, sont stockés dans la representation du type lui-meme et initialisé avant toute utilisation par le cctor. (et par extension est partagé par toutes les instances de ce type).

  10. #30
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Pourquoi stockées dans un fichier?
    Elles sont stockées en mémoire à une adresse qui n'est "liée" à aucune instance si je peux me permettre de parler ainsi.
    Exactement comme serait stockée une variable globale en C.
    En effet j'essayé d'imaginer où cela pouvait être stocké.
    Pour moi une instance d'une classe, cela veut dire que l'on a une petite zone mémoire représentant l'objet.
    Alors quand j'ai lu : classe static ne possède pas d'instance, j'en ai conclu pas de case mémoire.
    Bon assez basique comme résonnement, mais bon si les données sont bien stocké en mémoire, alors c'est comme une sorte d'instance unique pour tout le programme mais que l'on ne peut pas appeller instance .
    Je comprends mieux le problème et la comparaison avec le singleton.
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  11. #31
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Si tu preferes, il existe une initialisation pour tous les types que tu utilises, et independemment de toutes creations d'instance de ce type. Donc les valeurs placées en static, sont stockés dans la representation du type lui-meme et initialisé avant toute utilisation par le cctor. (et par extension est partagé par toutes les instances de ce type).
    Ok je comprends, c'est la différence avec le singleton.
    Bref on met les valeurs dans une case mémoire partagé par tout le monde que cela soit visible de toutes classes comme un type de données.
    En même temps je me demande du coup si ce n'est pas plus facile d'accés pour un pirate qui essayerais de pirater ton application, comme les variables globales en C ?
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  12. #32
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    je me demande du coup si ce n'est pas plus facile d'accés pour un pirate qui essayerais de pirater ton application, comme les variables globales en C
    Je me demande où tu as pêché ça... les variables globales sont pas plus faciles à pirater que les autres ! Ce serait même plutot le contraire, du moins dans le cas d'une attaque par buffer overflow.

  13. #33
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Je me demande où tu as pêché ça... les variables globales sont pas plus faciles à pirater que les autres ! Ce serait même plutot le contraire, du moins dans le cas d'une attaque par buffer overflow.
    Hum... désolé je ne suis pas spécialiste dans le domaine, j'ai juste encore confiance en mes anciens professeurs qui ne cessaient de répéter qu'une variable globale est un "cadeau" pour les pirates. Bien sur ils se gardent de nous dire pourquoi .
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  14. #34
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    je suis pas non plus spécialiste du hacking...
    moi aussi mes profs disaient de pas utiliser de variables globales, mais c'etait plutot parce que ce n'etait pas "propre"...

  15. #35
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Citation Envoyé par tomlev Voir le message
    je suis pas non plus spécialiste du hacking...
    moi aussi mes profs disaient de pas utiliser de variables globales, mais c'etait plutot parce que ce n'etait pas "propre"...
    Je pense aussi, cependant sans grande certitude n'etant pas un adepte du cracking, ceci dit, je pense que faire mumuse avec le memoire d'un process managé à la vue de l'usine à gaz qu'est .Net, ca doit pas etre de tout repos comparé au C. =p

  16. #36
    Membre actif
    Inscrit en
    Août 2006
    Messages
    381
    Détails du profil
    Informations forums :
    Inscription : Août 2006
    Messages : 381
    Points : 252
    Points
    252
    Par défaut
    Citation Envoyé par SirJulio Voir le message
    Salut,
    Comme le dirait le standard du CLI :
    Fields can be marked as static, indicating that the field is not part of values of the type but rather a location associated with the type as a whole. Locations for the static fields are created when the type is loaded and
    initialized when the type is initialized.
    Et quand le type est-il chargé en mémoire, lors de sa première utilisation dans l'application je suppose.

    Merci d'avance.
    Bye

  17. #37
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Points : 627
    Points
    627
    Par défaut
    Salut,

    si tu parles du chargement concret (lire l'assembly) du type, je suppose que cela se produit au lancement de l'application (quand la CLR va lire les metadatas et decouvrir ainsi les types, modules et assemblies). Si tu veux parler de l'initialisation, alors oui, tu es sur que les types statics seront initialisés, avant tout appel à un membre static de la classe, par le cctor. D'ailleurs, il y a certaines differences à noter entre le fait d'initialiser par un constructeur static explicite et d'initialiser les champs statics inline, notamment en ce qui concerne les types instanciables et possedant des champs statics. Plus de precisions sur cet article.

Discussions similaires

  1. [C#] Multiple instance d'une dll ayant des classes static
    Par Saroumane dans le forum Débuter
    Réponses: 0
    Dernier message: 04/06/2012, 17h49
  2. Réponses: 4
    Dernier message: 27/07/2007, 20h34
  3. Pb accès entre 2 classes static
    Par d.w.d dans le forum C++
    Réponses: 5
    Dernier message: 23/02/2005, 19h05
  4. [MFC] instance unique de dialogue non modale
    Par venomelektro dans le forum MFC
    Réponses: 5
    Dernier message: 02/02/2005, 12h41
  5. [VB6] [DLL] DLL à instance unique
    Par HPJ dans le forum VB 6 et antérieur
    Réponses: 9
    Dernier message: 19/09/2003, 08h07

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