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 :

Instanciation d'une classe d'une dll


Sujet :

C#

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2011
    Messages : 4
    Par défaut Instanciation d'une classe d'une dll
    Bonjour,

    Je vais essayer de vous exposer aussi clairement que possible mon problème.

    J'ai une dll avec :
    - une interface IPlugin du style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public interface IPlugin
    {
       int Add(int a, int b);
    }
    - une classe Class1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    public class Class1 : IPlugin
    {
        public Class1()
        {
            Console.WriteLine("--- constructor ---");
        }
     
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
    ainsi qu'une classe Factory avec une méthode Create me retournant une instance de Class1 sous forme d'IPlugin.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
       public class Factory
        {
            public Factory()
            {
     
            }
            static public IPlugin Create()
            {
                IPlugin plugin = new Class1();
                return plugin;
            }
        }
    Dans un projet exploitant cette dll, j'essai de récupérer la valeur de retour de la méthode Create et de le stocker dans un IPlugin grace a invoke.
    Seulement, j'ai à chaque fois un problème de cast du style
    Impossible d'effectuer un cast d'un objet de type 'Class1' en type 'IPlugin'.
    J'ai essayer de passer un parametre en reférence a ma fonction Create, d'utiliser Activator.CreateInstance mais rien ne change.

    Le but serait de faire un système de plugin a base de dll.
    J'ai cherché sur google avec acharnement mais je ne suis pas arrivé à résoudre ce problème.

    Quelqu'un aurait-il une solution à me proposer ?

    N'hésitez pas à me poser des questions si un des points ne vous semble pas clair.

    Merci d'avance.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    135
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 135
    Par défaut
    Problème typique des assemblies à noms faibles.

    Supposons que l'assembly contenant ton interface IPlugin soit Plugin.dll
    J'imagine qu'une fois que tu as chargé l'assembly contenant l'implémentation de ton plugin (appelons le Impl.dll), lorsque tu liste les modules chargés (AppDomain.CurrentDomain.GetJeSaisPlusQuoiLoadedAssemblies()), tu as deux fois Plugin.dll ?

    Ce qui se passe, c'est que lors du chargement de Impl.dll, la référence à Plugin.dll n'est pas résolue. Par conséquent, il recharge Plugin.dll une seconde fois en mémoire.
    Lors de ton Invoke, il crée une classe qui implémente le IPlugin se situant dans la seconde occurence de Plugin.dll, alors que ton cast fait référence à la première.

    Pour palier au problème, tu peux faire comme suit :

    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
     
     
    class Program{
     
              static Program(){
                        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
                        AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(CurrentDomain_TypeResolve);
              }
     
            static Assembly CurrentDomain_TypeResolve(object sender, ResolveEventArgs args)
            {
                return AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName == args.Name).FirstOrDefault();
            }
     
            static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
            {
                return AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName == args.Name).FirstOrDefault();
            }
    }

    PS : Ce code est à modifier selon tes besoins : Il gère les assemblies de plugins de manière un peu naive : Il suppose que deux classes de même noms ne peuvent pas exister dans deux assemblies différents. (ce qui est souvent le cas ! Enfin j'espère pour toi )


    Ou alors tu peux signer tes assemblies avec un nom fort, mais ça peut parfois s'avérer fastidieux...

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2011
    Messages : 4
    Par défaut
    J'ai qu'une seule dll contenant l'interface et la classe. Il faudrait faire deux dll ?
    C'est quoi les assembly à nom faible/fort ? (oui, j'ai commencé le c# ya peu de temps).
    Pour ce qui est de la classe que j'essaie d'instancier, si je passe la méthode Add en static et que je l'utilise sans avoir d'instance de la classe, ça fonctionne. J'avoue que je suis un peu perdu.

    J'ai rajouté AppDomain.CurrentDomain.GetAssemblies() et ma dll est effectivement présente deux fois.

    Je comprends pas a quoi ça sert d'avoir des méthodes statiques qui retournent un Assembly. C'est pour accéder à la bonne "version" de la dll ?

    Je comprends pas non plus comment récupérer une instance de ma classe avec ta méthode.

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    135
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 135
    Par défaut
    Moui, j’aurais dut commencer par là :

    Lorsqu'une classe est utilisée pour la première fois en .Net, si cette classe fait référence à d'autres classes (i.e. héritage, champs, arguments de methodes...), alors commence un processus de résolution des dépendances.
    Il ressemble à ça :

    - La classe référencée est recherchée dans les assemblies du GAC (Global Assembly Cache) - ce sont toutes les classes "communes" à toutes les applis de ton PC.
    - Ensuite, elle est recherchée parmis les assemblies chargés si l'assembly contenant la classe référencée a un nom fort
    - Elle est ensuite recherchée parmis les DLL qui sont dans le même dossier que l'assembly contenant la classe en cours d'initialisation


    Les methodes statiques "qui retournent des assemblies" que je t'ai montrées permettent de modifier ce comportement de recherche des dépendances.
    Elles sont appelées lorsqu'une classe est chargée, et que ses dépendances doivent être résolues.... ça te permet d'implémenter des comportements personnalisés !


    Pour les assemblies à nom fort : Fais des recherches sur google... c'est un système qui permet d'affecter à ton assembly un identifiant unique.


    Quels assemblies entrent en jeu ?

    Un exe + Une DLL ?
    Un exe + Deux DLL ?
    Qui est chargé par qui, et comment ? Par ajout de dépendances à la compilation ? Par Assembly.LoadFile() ?
    As tu mis tes DLLs de plugins dans un dossier différent de ton .exe ? (ça ne m'étonnerai pas : C'est typique d'un double chargement de ta dll : tu trouverais alors la version de ta dll dans ton dossier plugin, et une qui est dans ton dossier .exe)

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2011
    Messages : 4
    Par défaut
    Alors, j'ai deux projets, la dll et le prog de test (celui qui essaie d'accéder à la dll).
    J'ai donc un exe et une dll.
    Pour charger la dll, j'utilise Assembly.LoadFile en récupérant la dll directement dans le dossier du projet.
    ensuite je fait un GetType("Factory") puis un GetMethod("Create").
    Dès que j'ai tout ça je fais un invoke mais la valeur de retour est null. De meme si j'utilise Actiator.CreateInstanceFrom("Madll.dll", "Class1") ainsi que GetConstructor.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    135
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 135
    Par défaut
    Et j'imagine que ta dll est déjà référencée dans ton exe ?

    Ce qui se passe : Lors du chargement de l'exe, les références sont aussi chargées en mémoire.
    Par conséquent, ta dll est chargée.

    Ensuite, tu REcharges ta DLL via Assembly.LoadFile() ... d'où la duplication de l'assembly.

    En l'occurence, comme ta dll est référencée, tu sais qu'elle sera chargée. donc pas besoin d'Assembly.LoadFile()
    Utilises plutot

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    var assembly = AppDomain.Current.GetAssemblies().Where(a=>new FileInfo(a.Location).Equals(new FileInfo("MaDll.dll"))).First();
    assembly.GetType("Factory") //etc..etc... mais pas de LoadFile !

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2011
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2011
    Messages : 4
    Par défaut
    J'ai cherché dans la doc du msdn et j'ai finalement tout changé. Maintenant j'utilise la MEF qui semble etre fait pour ça et tout à l'air de marcher.

    Merci beaucoup pour votre aide

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    135
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 135
    Par défaut
    La MEF ? Tu parles de ça ?

Discussions similaires

  1. [C#]Accéder à une methode dans une classe d'une DLL externe
    Par Greg34000 dans le forum Services Web
    Réponses: 3
    Dernier message: 28/03/2013, 15h54
  2. Réponses: 7
    Dernier message: 11/03/2010, 10h13
  3. Eval d'une propriété d'une classe dans une classe
    Par bizet dans le forum ASP.NET
    Réponses: 4
    Dernier message: 28/10/2008, 09h43
  4. Réponses: 2
    Dernier message: 31/08/2005, 16h12
  5. Réponses: 4
    Dernier message: 17/03/2004, 17h24

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