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 :

Lier/Appeler une assembly à la volé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 Lier/Appeler une assembly à la volée ?
    Bonjour,

    J'ai un projet customisable.

    J'expose une interface, et j'aimerais, en fonction d'un paramètre, d'un choix utilisateur, etc. pouvoir appeler la DLL qui implémente l'interface qui va bien.

    Voici quelques extraits de code :

    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
     
    // Project dependencies
    using CommonTools; // Défini l'interface IExtractor
    using UpdateTools;  // Contient une classe qui implémente IExtractor dans le contexte Update CRM
    using GoogleTools;  // Contient une classe qui implémente IExtractor dans le contexte Google
    using ZimbraTools;  // Contient une classe qui implémente IExtractor dans le contexte Zimbra
     
    [...]
     
                    // Choose the right external program
                    IExtractor External;
                    switch (Properties.Settings.Default.ExternalType)
                    {
                        case "Google":
                            External = new GoogleExtractor();
                            break;
                        case "Zimbra":
                            External = new ZimbraExtractor();
                            break;
                        case "Update":
                            External = new UpdateExtractor();
                            break;
                        default:
                            External = null;
                            break;
                    }
    J'ai pas envie :
    - de compiler le programme unitairement pour chaque programme externe
    - de fournir l'ensemble des DLL au client
    - d'avoir une liste de 20 kilomètres de références inutiles (seule une assembly sera utilisée en fonction du paramétrage)

    Du coup, j'aimerais remplacer le code précédent par un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // Project dependencies
    using CommonTools; // Défini l'interface IExtractor
    // Je ne référence plus rien d'autre
     
    [...]
     
                    // Choose the right external program
                    IExtractor External new Assembly(Properties.Settings.Default.ExternalType);
    Ça existe ? Quelle syntaxe ? Usine à gaz ?

  2. #2
    Invité
    Invité(e)
    Par défaut
    Je ne sais pas si tu connais l'Injection de dépendances mais je pense que c'est la solution à ton problème.

    Il y a une panoplie d'API qui permettent de mettre ce un principe de développement orienté objet.

  3. #3
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut
    bonjour

    Cette usine à gaz s'appelle MEF NetFramework 4.0 (managed extensibilyty framework) qui sera peut etre ton ami...

    voici un exemple:
    -un assembly "Contracts" qui contient une interface IMyComponent (projet lib à part)...
    -un assembly "ExportingLib1" qui contient un class TestComponent1 (projet lib ExportingLib1)
    -un assembly "ExportingLib2" qui contient un class TestComponent2 (projet lib ExportingLib2) les 2 implementant IMyComponent...

    -un assembly "ImportingLib" qui contient un class Importer (projet lib ImportingLib)...c'est le -manager-qui utilise le MEF...
    Il est en charge de :
    -fetcher le dossier application client...
    -charger l'assembly "Contracts"(interface)
    -charge tous les assemblies "ExportingLib" trouvees...
    -utilise MEF pour cree le class approprie suivant le "ExportingLib1" ..ou..ou...ou... le "ExportingLib3" trouvee !!!!...Il se debrouille avec ce qu'il trouve...

    En fait ton dossier appli client contiendra 3 assemblies:
    -Contracts.dll
    -ImportingLib.dll
    -Exportinglib1.dll (UpdateTools) ou Exportinglib2.dll (GoogleTools) ou Exportinglib3.dll (ZimbraTools)

    voici un code avec
    -interface IMyComponent (projet lib Contracts)
    -class TestComponent1 (projet lib ExportingLib1)
    -class TestComponent2 (projet lib ExportingLib2)
    -class Importer (projet lib ImportingLib)


    code behind .cs de projet lib Contracts(simple interface):
    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    namespace Contracts
    {
        public interface IMyComponent
        {
            string Description { get; }
            string ManipulateString(string a, string b);
        }
     
    }
    code behind .cs de ExportingLib1(class ):

    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    //ajout ref au projet lib Contracts
    using Contracts;
    //ajout ref à assembly System.ComponentModel.Composition(c'est le MEF)
    using System.ComponentModel.Composition;
     
    namespace ExportingLib1
    {
        [Export(typeof(IMyComponent))]
        public class TestComponent1 : IMyComponent
        {
            #region IMyComponent Members
            public string Description
            {
                get { return "Concatenates a and b"; }
            }
     
            public string ManipulateString(string a, string b)
            {
                return string.Concat(a, b);
            }
            #endregion
        }
    }
    code behind .cs de ExportingLib2(class ):

    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    //ajout ref au projet lib Contracts
    using Contracts;
    //ajout ref à assembly System.ComponentModel.Composition(c'est le MEF)
    using System.ComponentModel.Composition;
     
     
     
    namespace ExportingLib2
    {
        [Export(typeof(IMyComponent))]
        public class TestComponent2 : IMyComponent
        {
            #region IMyComponent Members
            public string Description
            {
                get { return "Removes b from a"; }
            }
     
            public string ManipulateString(string a, string b)
            {
                return a.Replace(b, string.Empty);
            }
            #endregion
        }
    }
    code behind .cs de projet lib ImportingLib(class manager du MEF):

    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
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    //ajout ref au projet lib Contracts
    using Contracts;
    //ajout ref à assembly System.ComponentModel.Composition(c'est le MEF)
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Reflection;
    using System.IO;
     
     
     
    namespace ImportingLib
    {
        //contain the host, hosts and calls the components
        public class Importer
        {
            [ImportMany(typeof(IMyComponent))]
            private IEnumerable<IMyComponent> operations;
     
            public void DoImport()
            {
                //An aggregate catalog that combines multiple catalogs
                var catalog = new AggregateCatalog();
                //Adds all the parts found in all assemblies in 
                //the same directory as the executing program
                catalog.Catalogs.Add(
                new DirectoryCatalog(
                Path.GetDirectoryName(
                    Assembly.GetExecutingAssembly().Location)));
     
                //Create the CompositionContainer with the parts in the catalog
                CompositionContainer container = new CompositionContainer(catalog);
     
                //Fill the imports of this object
                container.ComposeParts(this);
            }
     
            public int AvailableNumberOfOperations
            {
                get
                {
                return (operations != null ? operations.Count() : 0);
                }
            }
     
            public List<string> CallAllComponents( string a, string b)
            {
                var result = new List<string>();
                foreach( var op in operations )
                {
                Console.WriteLine(op.Description);
                result.Add( op.ManipulateString(a,b ));
                }
                return result;
            }
        }
    }
    code behind .cs du form de test (nb: je n'ai reference expres que ExportingLib1 pour voir comment il cree automatiquement une instance TestComponent1 ):

    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
     
     
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    //ajout reference à assembly ImportingLib & ExportingLib1
    using ImportingLib;
    using ExportingLib1;
    //cet ref a ete omise expres pour ne pas distribuer l'assembly ExportingLib2
    //using ExportingLib2;
    namespace WinApp
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
     
            private void button1_Click(object sender, EventArgs e)
            {
                Importer imp = new Importer();
                imp.DoImport();
                textBox1.Text = imp.AvailableNumberOfOperations.ToString();
     
                List<string> l = imp.CallAllComponents("stringbuilder", "builder");
               foreach (var item in l)
               {
                   textBox2.Text =textBox2.Text + item + Environment.NewLine;
     
               }
     
            }
        }
    }
    bon code...

  4. #4
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bonjour.

    Fondamentalement, pour créer une application modulaire il suffit de décider quels types le plugin devra consommer et notamment implémenter, puis les placer dans une assemblée qui sera commune aux plugins et à l'application. Par exemple une interface IPlugin. Partant de là on utilisera Assembly.Load pour charger l'assemblée et scanner tous les types à la recherche de ceux implémentant IPlugin (Type.IsAssignableFrom), que l'on instanciera ensuite via Activator.CreateInstance.

    Tout ça n'a rien de très sorcier. En revanche cela amène naturellement des problèmes à résoudre : la question du contrôle (qui du plugin ou de l'application réalise les détails de la connexion entre les deux ?), la découverte ou l'enregistrement des plugins (scanner une assemblée est lent), la compatibilité de l'appli avec des plugins écrits pour des versions plus anciennes avec des services qui ont depuis disparu tandis que d'autres qui sont apparus, etc. Bref, il y a une petite infrastructure à mettre en place. Ça peut être simple ou très compliqué selon les besoins.

    MEF est une proposition d'infrastructure de ce genre et c'est la plus récente des créations de MS dans ce domaine (oui, il y en a eu plusieurs, le sujet est casse-gueule). Elle est mise en oeuvre au sein des dernières versions de Visual Studio lui-même (pour créer VS). C'est une usine à gaz mais ça fonctionne. Voici un excellent lien issu de mes favoris sur MEF.

    Enfin MEF ou toute autre solution ne dispensera pas de la tâche la plus compliquée dans ce domaine : définir la séparation entre l'application et la base commune, et exposer tout ce dont les plugins auront besoin pour faire leur job. Le tout sans pourrir l'architecture en place de préférence.

Discussions similaires

  1. Réponses: 1
    Dernier message: 14/11/2010, 16h42
  2. Récupérer l'assembly qui a appelé une méthode
    Par bossun dans le forum Windows Forms
    Réponses: 2
    Dernier message: 02/07/2010, 18h08
  3. [débutant]Faire appel à une action d'une ActionList
    Par petitours dans le forum C++Builder
    Réponses: 6
    Dernier message: 12/03/2004, 22h53
  4. [JSP] Appeler une fonction
    Par Patrick95 dans le forum Servlets/JSP
    Réponses: 10
    Dernier message: 23/12/2003, 13h44
  5. Appeler une fonction avec/sans parenthèses
    Par haypo dans le forum Algorithmes et structures de données
    Réponses: 8
    Dernier message: 29/12/2002, 18h48

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