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

Windows Forms Discussion :

Une variable qui référence une classe et non une instance de classe


Sujet :

Windows Forms

  1. #1
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut Une variable qui référence une classe et non une instance de classe
    Salut tout le monde,

    ma question est plus sur le langage C# en lui-même que sur les forms, désolé de poster ici mais je n'ai pas trouvé de meilleur endroit pour la poser.

    Je viens du Delphi et en Delphi il est possible de déclarer une variable et la faire pointer vers une classe, non vers un objet (une instance de la classe), en d'autres termes, je n'affecte pas un nouvel objet avec new ou un objet existant à ma variable mais la déclaration d'une classe ou d'une de ses filles.
    Je n'arrive pas à faire la même chose en C#, hors comme il est bien plus récent, je pense qu'il est possible de faire la même chose.
    Pour l'instant, je n'ai pas trouvé comment faire dans l'aide du C#.

    Mes questions sont donc, est-ce possible ? Et si oui, comment ?

    PS : pour ceux qui se demandent à quoi cela sert, voici un exemple, j'ai une classe mère Tableur qui possède certains algos, et 2 classes filles, Excel et OpenOffice qui dérivent de Tableur et qui surchargent les méthodes d'accès, de lecture et d'écriture des données dans le tableur. Je fais un projet pour Excel, un autre pour OpenOffice, au début du projet, il suffit de déclarer le type de la classe fille utilisée et chaque fois que j'ai besoin d'instancier une référence, je n'ai pas besoin de faire de if ni de switch pour savoir quel constructeur appeler.

    PPS : un autre exemple d'utilisation est possible en Delphi mais pas en C# car la notion de méthode statique virtuelle n'existe pas.

    Hop, je viens de réfléchir (et oui je sais que ça sert de temps en temps), je pense que j'ai une solution, un peu laborieuse peut-être mais qui devrait marcher.
    Utiliser le design pattern singleton pour créer une instance de ma classe en private, l'instancier avec un constructeur statique en début de projet (donc suivant la classe fille que je désire), puis faire des méthodes statiques qui vont appeler des méthodes virtuelles de ma classe.
    C'est tiré par les cheveux mais ça risque de fonctionner. Si quelqu'un a une solution plus simple, je suis preneur, si par exemple c'est nativement possible dans le langage.

  2. #2
    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
    Ce qui caractérise une classe, c'est son type. Une variable Type, que tu affectes avec typeof(TaClasse) et zou. D'ailleurs les generics devraient également satisafire tes besoins.
    ಠ_ಠ

  3. #3
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 277
    Points : 1 521
    Points
    1 521
    Par défaut
    Il faudrait p'tet penser au DP Factory.

  4. #4
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    J'ai essayé avec Type et typeof, mais j'ai un message d'erreur à la compilation.
    Voici le code que j'ai fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            public int Test()
            {
                Type t = typeof(Tableur);
                t = OpenOffice;
                Tableur r = new t();
            }
    OpenOffice est une classe qui dérive de Tableur.
    Le premier message d'erreur est :
    'MonEspace.OpenOffice' is a 'type' but is used like a 'variable'
    Comment puis-je créer r du type OpenOffice en utilisant t ?

  5. #5
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Pour utiliser un DP Factory, il faut que je déclare toutes les classes filles de ma classe mère dans le DP Factory, hors je ne le souhaite pas.
    J'ai un projet spécifique pour Excel et un autre pour OpenOffice.
    Dans un projet, je ne souhaite pas avoir tout le code spécifique de l'autre projet, je souhaite séparer complètement les 2 projets (en tout cas leur partie spécifique).

  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 277
    Points : 1 521
    Points
    1 521
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Type t = typeof(OpenOffice);
    Tableur r = Activator.CreateInstance(t);

  7. #7
    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
    Generics ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    private void Test<T>() where T : Tableur, new()
    {
        //....
        Tableur r = new T();
        //....
    }
    Tu appelles ensuite Test via Test<OpenOffice> ou Test<Excel>.
    ಠ_ಠ

  8. #8
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Merci pour votre aide, ça m'aide beaucoup, je sais maintenant ce que je cherche.

    Avec Activator.CreateInstance(t), ça fonctionne en rajoutant un cast, le seul problème dans tout ça est qu'on ne peut pas spécifier à la déclaration de t (Type t) est qu'il ne devrait pouvoir référencer que les classes Tableur et ses filles, on n'a pas de vérification mis à part lors du castage avec Activator.

    Avec le code générique, je n'arrive pas à le faire fonctionner, car je dois pouvoir appeler Test en passant en paramètre <t> et non en dur, <OpenOffice> ou <Excel>.
    J'ai essayé le code Test<t> et j'obtiens ce message d'erreur à la compilation :
    The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)

  9. #9
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 277
    Points : 1 521
    Points
    1 521
    Par défaut
    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
     
     
    public class Factory {
     
       private Type type;
     
       public Factory(string type) {
          this.type = Type.GetType(type);
       }
     
       public Tableur Create() {
          return (Tableur)Activator.CreateInstance(t);
       }
     
    }
    et en déclarant cette factory en statique dans le code ?

  10. #10
    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 WebPac Voir le message
    Avec le code générique, je n'arrive pas à le faire fonctionner, car je dois pouvoir appeler Test en passant en paramètre <t> et non en dur, <OpenOffice> ou <Excel>.
    J'ai essayé le code Test<t> et j'obtiens ce message d'erreur à la compilation :
    Mais dans une fonction Test<T>(int i), T est un paramètre, comme i. Il est un peu spécial, mais c'est un paramètre... Je n'ai pas analysé à fond ton problème, mais je ne pense pas qu'il soit tellement complexe qu'on ait besoin explicitement du type "t", dans une variable, de ta classe.
    ಠ_ಠ

  11. #11
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Mais dans une fonction Test<T>(int i), T est un paramètre, comme i. Il est un peu spécial, mais c'est un paramètre... Je n'ai pas analysé à fond ton problème, mais je ne pense pas qu'il soit tellement complexe qu'on ait besoin explicitement du type "t", dans une variable, de ta classe.
    Je suis désolé mais quand j'essaie ton code, j'ai ce message d'erreur à la compilation :
    The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)
    Alors que t est bien déclaré ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Type t = typeof(OpenOffice);
    Kaidan, j'ai trouvé une méthode qui me vérifie le type pour qu'elle soit bien une classe dérivant de Tableur, finalement, on peut très bien faire la fabrique comment étant une méthode statique de Tableur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public abstract class Tableur
    {
        public static Tableur Factory(Type t)
        {
            if (t.IsSubclassOf(typeof(Tableur)))
                return Activator.CreateInstance(t) as Tableur;
            else
                return null;
        }
    }
    Avec t la variable initialisée au début du projet, qu'on la passe en paramètre ou bien qu'on la retrouve en global.

  12. #12
    Rédacteur
    Avatar de Greybird
    Inscrit en
    Juin 2002
    Messages
    673
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 673
    Points : 1 271
    Points
    1 271
    Par défaut
    Citation Envoyé par WebPac Voir le message
    Je suis désolé mais quand j'essaie ton code, j'ai ce message d'erreur à la compilation :

    Alors que t est bien déclaré ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Type t = typeof(OpenOffice);
    L'instanciation dynamique d'un type générique se fait de manière un peu particulière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int i;
    Type genericDefinitionType = typeof(Test<>);
    Type[] typeArgs = { typeof(OpenOffice) };
    Type genericType = genericDefinitionType.MakeGenericType(typeArgs);
    return Activator.CreateInstance(genericType, i);

  13. #13
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Citation Envoyé par Greybird Voir le message
    L'instanciation dynamique d'un type générique se fait de manière un peu particulière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    int i;
    Type genericDefinitionType = typeof(Test<>);
    Type[] typeArgs = { typeof(OpenOffice) };
    Type genericType = genericDefinitionType.MakeGenericType(typeArgs);
    return Activator.CreateInstance(genericType, i);
    Merci pour l'info, mais finalement, on revient sur le code de départ avec l'Activator.CreateInstance, est-ce bien nécessaire d'utiliser les génériques dans ce cas ?

  14. #14
    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,

    Vu qu'apparement ce sont des projets distincts pourquoi ne pas jouer simplement sur des namespaces. exemple :

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    #define _Excel
     
    using System;
    using CommonTableur;
     
    #if _Excel
    using Excel;
    #else
    using OpenOffice;
    #endif
     
     
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                ITableur t = new Tableur();
                t.Machin();
                t.Truc();
            }
        }
     
     
    }
     
    namespace CommonTableur
    {
        interface ITableur
        {
            void Truc();
            void Machin();
        }
     
    }
    namespace OpenOffice
     
    {
        class Tableur : CommonTableur.ITableur
        {
            #region ITableur Members
            public void Truc()
            {
                Console.WriteLine("Truc Open");
            }
     
            public void Machin()
            {
                Console.WriteLine("Machin Open");
            }
            #endregion
        }
    }
     
    namespace Excel
    {
        class Tableur : CommonTableur.ITableur
        {
            #region ITableur Members
            public void Truc()
            {
                Console.WriteLine("Truc Excel");
            }
     
            public void Machin()
            {
                Console.WriteLine("Machin Excel");
            }
            #endregion
        }
    }
    Si tu commentes le define en haut, ton le Tableur sera celui d'openoffice et Excel si tu laisses le define. Ici, c'est avec une interface mais on peut imaginer le meme fonctionnement avec une classe mere et des filles, chacun dans leurs namespace.

    En esperant que ca aide, bon courage. =)

  15. #15
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Salut SirJulio,

    ton idée est bonne, je me sers également des namespaces, mais le problème dans ton code est que tu instancies toujours t en Tableur (la classe mère) et non suivant une des 2 classes filles en fonction du projet (Excel ou OpenOffice), donc les méthodes Machin et Truc appeleront celles de la classe mère Tableur.

  16. #16
    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
    Pour reprendre le schema qu'apparement tu utilises (ici une mere abstract (deux meths abstracts), et deux filles selon le tableur) :

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    #define _Excel
     
    using System;
    using CommonTableur;
     
    #if _Excel
    using Excel;
    #else
    using OpenOffice;
    #endif
     
     
    namespace ConsoleApplication1
    {
        class Program
        {
            static unsafe void Main(string[] args)
            {
                Tableur t = new TableurFille();
                t.Machin();
                t.Truc();
                t.Generale();
            }
        }
     
     
    }
     
    namespace CommonTableur
    {
        abstract class Tableur
        {
            public abstract void Truc();
            public abstract void Machin();
     
            public void Generale()
            {
                Console.WriteLine("Tableur general");
            }
        }
     
    }
    namespace OpenOffice
     
    {
        class TableurFille : CommonTableur.Tableur
        {
            #region Tableur Members
            public override void Truc()
            {
                Console.WriteLine("Truc Open");
            }
     
            public override void Machin()
            {
                Console.WriteLine("Machin Open");
            }
            #endregion
        }
    }
     
    namespace Excel
    {
        class TableurFille : CommonTableur.Tableur
        {
            #region Tableur Members
            public override void Truc()
            {
                Console.WriteLine("Truc Excel");
            }
     
            public override void Machin()
            {
                Console.WriteLine("Machin Excel");
            }
            #endregion
        }
    }
    Suivant mon define j'aurai bien la classe file souhaitée (la differenciation des filles ne se faisant pas sur le nom, puisqu'elle porte le meme, mais sur le namespace explicitement utilisé). Pas besoin d'adapter la reference utilisé pour la manip puisque les methodes specifiques sont abstracts, et suivant le define fixé à la compil tu utiliseras bien la bonne fille.

    Ca me parait correspondre à la problematique, mais j'ai peut etre compris de travers. =)

  17. #17
    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 WebPac Voir le message
    Je suis désolé mais quand j'essaie ton code, j'ai ce message d'erreur à la compilation :

    Alors que t est bien déclaré ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Type t = typeof(OpenOffice);
    Les generics ne nécessitent pas de créer de variable de type "Type". Juste, dans un projet, tu appelles Test<Excel>, et dans un autre, Test<OpenOffice>.
    ಠ_ಠ

  18. #18
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Salut,

    en effet ta solution répond au problème mais elle me dérange, je ne sais pas s'il est conseillé ou déconseillé de déclarer 2 classes filles dérivant de la même mère ayant le même nom dans 2 espaces de nom différents mais ça me perturbe et je me dis que c'est source de confusion et de bug.

    Je préfère continuer à travailler avec 2 filles ayant des noms explicites et différents.

  19. #19
    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 WebPac Voir le message
    Salut,

    en effet ta solution répond au problème mais elle me dérange, je ne sais pas s'il est conseillé ou déconseillé de déclarer 2 classes filles dérivant de la même mère ayant le même nom dans 2 espaces de nom différents mais ça me perturbe et je me dis que c'est source de confusion et de bug.

    Je préfère continuer à travailler avec 2 filles ayant des noms explicites et différents.
    A ce moment là, tu peux utiliser un autre aspect de "using" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #if Excel
    using ClasseFille = Excel.ClasseMachin;
    #else
    using ClasseFille = OpenOffice.ClasseBidule;
    #endif
    ಠ_ಠ

  20. #20
    Membre confirmé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Points : 512
    Points
    512
    Par défaut
    Citation Envoyé par Guulh Voir le message
    Les generics ne nécessitent pas de créer de variable de type "Type". Juste, dans un projet, tu appelles Test<Excel>, et dans un autre, Test<OpenOffice>.
    Ok mais ça pose problème car justement je dois pouvoir l'appeler sans mettre en dur une classe.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 13
    Dernier message: 07/11/2011, 15h41
  2. Réponses: 2
    Dernier message: 13/11/2008, 14h07
  3. Exploiter le nom d'une classe contenu dans une variable
    Par 84mickael dans le forum Langage
    Réponses: 2
    Dernier message: 15/06/2006, 14h23
  4. Contenu d'une variable qui disparait :/
    Par Aleksis dans le forum C++
    Réponses: 10
    Dernier message: 02/06/2006, 15h50
  5. Réponses: 4
    Dernier message: 13/05/2006, 11h18

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