Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

CRÉATION DYNAMIQUE D'OBJETS


Information sur la source

Catégorie :.NET Source .NET ( DotNet ) Classé sous : dynamique, reflection, plugins Niveau : Initié Date de création : 19/02/2007 Date de mise à jour : 20/02/2007 15:53:21 Vu / téléchargé: 6 119 / 389

Note :
Aucune note

Commentaire sur cette source (10)
Ajouter un commentaire et/ou une note

Description

Ce code sert à lire dans un répertoire l'ensemble des DLL et à les ajouter si elles correspondent à une interface ou dérivent d'un type donné.
J'utilise pour cela la reflexion.
Ceci peut permettre de créer des plugins.
La solution est composée de 3 projets, un executable qui contient le code de recherche des DLL, une DLL qui contient de type de référence (référencé dans l'exe) et une DLL qui contient les types dérivés (inconnue de l'exe).
Une propriété statique de la classe de base peut servir de clef, sinon, c'est le nom de la classe qui aura cette fonction.

 

Source

  • class Loader<BaseClass>
  • {
  • private Dictionary<string, Type> creatable;
  • private Type BaseType;
  • private string KeyElement;
  • private string defaultElement;
  • #region constructeurs
  • /// <summary>
  • /// Créé un chargeur de classe
  • /// </summary>
  • public Loader() : this("") { ;}
  • /// <summary>
  • /// Créé un chargeur de classes
  • /// </summary>
  • /// <param name="KeyElement">Element servant de clef</param>
  • public Loader(string KeyElement)
  • {
  • this.BaseType = typeof(BaseClass);
  • this.KeyElement = KeyElement;
  • creatable = new Dictionary<string,Type>();
  • }
  • #endregion
  • #region gestion des types
  • /// <summary>
  • /// Ajoute toutes les classes contenues dans toutes les assemblies d'un répertoire
  • /// </summary>
  • /// <param name="Path">Chemin Contenant les assemblies à charger</param>
  • public void AddFolder(string Path) {
  • //Charge les fichiers contenus dans le répertoire
  • DirectoryInfo directory = new DirectoryInfo(Path);
  • foreach (FileInfo file in directory.GetFiles("*.dll"))
  • {
  • AddAssembly(file.FullName);
  • }
  • }
  • /// <summary>
  • /// Ajoute toutes les classes contenues dans une assembly
  • /// </summary>
  • /// <param name="Path"></param>
  • public void AddAssembly(string Path)
  • {
  • //Charge l'assembly
  • Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(Path)); ;
  • //Récupère tous les type contenus
  • Type[] types = assembly.GetTypes();
  • foreach (Type type in types)
  • {
  • AddType(type);
  • }
  • }
  • /// <summary>
  • /// Ajoute un type
  • /// </summary>
  • /// <param name="type">Type à ajouter</param>
  • private void AddType(Type type)
  • {
  • //Vérifie que le type dérive bien de la classe de base
  • if (!IsBasedOn(type,BaseType)) return;
  • //Récupère la valeur clef (nom de la classe si le nom est null)
  • string key;
  • if (string.IsNullOrEmpty(KeyElement)) {
  • key = type.FullName;
  • } else {
  • key = type.InvokeMember(KeyElement, BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy | BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public, null, null, null).ToString();
  • }
  • //inscrit la classe dans la liste
  • creatable[key] = type;
  • }
  • /// <summary>
  • /// Ajoute un type
  • /// </summary>
  • /// <param name="Path">Chemin de l'assembly contenant la classe</param>
  • /// <param name="ClassName">Nom de la classe</param>
  • private void AddType(string Path, string ClassName)
  • {
  • //Charge l'assembly
  • Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(Path));
  • //charge le type particulier
  • Type type = assembly.GetType(ClassName);
  • //Ajoute le type
  • AddType(type);
  • }
  • /// <summary>
  • /// Retire un type de la liste
  • /// </summary>
  • /// <param name="Id">Clef du type à enlever</param>
  • public void RemoveType(string Id)
  • {
  • creatable.Remove(Id);
  • }
  • #endregion
  • #region divers
  • /// <summary>
  • /// Défini une classe par défaut si la classe recherchée n'existe pas
  • /// </summary>
  • public string DefaultElement
  • {
  • get { return defaultElement; }
  • set { defaultElement = value; }
  • }
  • /// <summary>
  • /// Vérifie si une classe est basée ou dérivée d'un type particulier
  • /// </summary>
  • /// <param name="TestType">Type à tester</param>
  • /// <param name="BaseType">Référence</param>
  • /// <returns></returns>
  • private bool IsBasedOn(Type TestType, Type BaseType) {
  • if (TestType.IsSubclassOf(BaseType)) return true;
  • if (TestType.FullName == BaseType.FullName) return true;
  • if (Type.Equals(TestType, typeof(System.Object))) return false;
  • return IsBasedOn(TestType.BaseType, BaseType);
  • }
  • #endregion
  • #region creation de types
  • /// <summary>
  • /// Créé une instance de l'élément demandé, s'il n'existe pas, créé une instance de l'élément par défaut.
  • /// </summary>
  • /// <param name="Id">Identifiant de l'élément à créer</param>
  • /// <param name="parameters">Paramètres du constructeur</param>
  • /// <returns>Objet de la classe de base</returns>
  • public BaseClass Create(string Id, params object[] parameters)
  • {
  • object Obj;
  • try {
  • Obj = Activator.CreateInstance(creatable[Id], parameters);
  • } catch {
  • try {
  • Obj = Activator.CreateInstance(creatable[defaultElement], parameters);
  • } catch {
  • throw new System.Reflection.ReflectionTypeLoadException(null, null, "Impossible de créer l'objet, la clef n'existe pas");
  • }
  • }
  • return (BaseClass)Obj;
  • }
  • #endregion
  • }
class Loader<BaseClass> 
{
    private Dictionary<string, Type> creatable;
    private Type BaseType;
    private string KeyElement;
    private string defaultElement;

    #region constructeurs

    /// <summary>
    /// Créé un chargeur de classe
    /// </summary>
    public Loader() : this("") { ;}

    /// <summary>
    /// Créé un chargeur de classes
    /// </summary>
    /// <param name="KeyElement">Element servant de clef</param>
    public Loader(string KeyElement)
    {
        this.BaseType = typeof(BaseClass);
        this.KeyElement = KeyElement;
        creatable = new Dictionary<string,Type>();
    }

    #endregion

    #region gestion des types
    /// <summary>
    /// Ajoute toutes les classes contenues dans toutes les assemblies d'un répertoire
    /// </summary>
    /// <param name="Path">Chemin Contenant les assemblies à charger</param>
    public void AddFolder(string Path) {
        //Charge les fichiers contenus dans le répertoire
        DirectoryInfo directory = new DirectoryInfo(Path);
        foreach (FileInfo file in directory.GetFiles("*.dll"))
        {
            AddAssembly(file.FullName);
        }
    }

    /// <summary>
    /// Ajoute toutes les classes contenues dans une assembly
    /// </summary>
    /// <param name="Path"></param>
    public void AddAssembly(string Path)
    {
        //Charge l'assembly
        Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(Path)); ;
        //Récupère tous les type contenus
        Type[] types = assembly.GetTypes();
        foreach (Type type in types)
        {
            AddType(type);
        }
    }

    /// <summary>
    /// Ajoute un type
    /// </summary>
    /// <param name="type">Type à ajouter</param>
    private void AddType(Type type)
    {
        //Vérifie que le type dérive bien de la classe de base
        if (!IsBasedOn(type,BaseType)) return;
        //Récupère la valeur clef (nom de la classe si le nom est null)
        string key;
        if (string.IsNullOrEmpty(KeyElement)) {
            key = type.FullName;
        } else {
            key = type.InvokeMember(KeyElement, BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy | BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public, null, null, null).ToString();
        }
        //inscrit la classe dans la liste
        creatable[key] = type;
    }

    /// <summary>
    /// Ajoute un type
    /// </summary>
    /// <param name="Path">Chemin de l'assembly contenant la classe</param>
    /// <param name="ClassName">Nom de la classe</param>
    private void AddType(string Path, string ClassName)
    {
        //Charge l'assembly
        Assembly assembly = Assembly.Load(AssemblyName.GetAssemblyName(Path));
        //charge le type particulier
        Type type = assembly.GetType(ClassName);
        //Ajoute le type
        AddType(type);
    }

    /// <summary>
    /// Retire un type de la liste
    /// </summary>
    /// <param name="Id">Clef du type à enlever</param>
    public void RemoveType(string Id)
    {
        creatable.Remove(Id);
    }   
    #endregion

    #region divers
    /// <summary>
    /// Défini une classe par défaut si la classe recherchée n'existe pas
    /// </summary>
    public string DefaultElement
    {
        get { return defaultElement; }
        set { defaultElement = value; }
    }

    /// <summary>
    /// Vérifie si une classe est basée ou dérivée d'un type particulier
    /// </summary>
    /// <param name="TestType">Type à tester</param>
    /// <param name="BaseType">Référence</param>
    /// <returns></returns>
    private bool IsBasedOn(Type TestType, Type BaseType) {
        if (TestType.IsSubclassOf(BaseType)) return true;
        if (TestType.FullName == BaseType.FullName) return true;
        if (Type.Equals(TestType, typeof(System.Object))) return false;
        return IsBasedOn(TestType.BaseType, BaseType);
    }

    #endregion

    #region creation de types
    /// <summary>
    /// Créé une instance de l'élément demandé, s'il n'existe pas, créé une instance de l'élément par défaut.
    /// </summary>
    /// <param name="Id">Identifiant de l'élément à créer</param>
    /// <param name="parameters">Paramètres du constructeur</param>
    /// <returns>Objet de la classe de base</returns>
    public BaseClass Create(string Id, params object[] parameters)
    {
        object Obj;
        try {
            Obj = Activator.CreateInstance(creatable[Id], parameters);
        } catch {
            try {
                Obj = Activator.CreateInstance(creatable[defaultElement], parameters);
            } catch {
                throw new System.Reflection.ReflectionTypeLoadException(null, null, "Impossible de créer l'objet, la clef n'existe pas");
            }
        }
        return (BaseClass)Obj;
    }

    #endregion
}

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !
  •   TestDynamique
    •   BaseBibliotheque
    •   TestBibliotheque
      •   bin
        •   Debug
          • BaseBibliotheque.dllTélécharger ce fichier [Réservé aux membres club]16 384 octets
          • BaseBibliotheque.pdbTélécharger ce fichier [Réservé aux membres club]11 776 octets
          • TestBibliotheque.dllTélécharger ce fichier [Réservé aux membres club]16 384 octets
          • TestBibliotheque.pdbTélécharger ce fichier [Réservé aux membres club]15 872 octets
      •   obj
        •   Debug
          •   Refactor
            • TestBibliotheque.dllTélécharger ce fichier [Réservé aux membres club]16 384 octets
          • TempPE
          • ResolveAssemblyReference.cacheTélécharger ce fichier [Réservé aux membres club]2 744 octets
          • TestBibliotheque.dllTélécharger ce fichier [Réservé aux membres club]16 384 octets
          • TestBibliotheque.pdbTélécharger ce fichier [Réservé aux membres club]15 872 octets
        • TestBibliotheque.csproj.FileList.txtTélécharger ce fichier [Réservé aux membres club]Voir ce fichier234 octets
      •   Properties
      • ClassDiagram1.cdTélécharger ce fichier [Réservé aux membres club]1 040 octets
      • CTest1.csTélécharger ce fichier [Réservé aux membres club]Voir ce fichier358 octets
      • CTest2.csTélécharger ce fichier [Réservé aux membres club]Voir ce fichier356 octets
      • CTest3.csTélécharger ce fichier [Réservé aux membres club]Voir ce fichier243 octets
      • TestBibliotheque.csprojTélécharger ce fichier [Réservé aux membres club]Voir ce fichier2 351 octets
    •   TestDynamique
    • TestDynamique.slnTélécharger ce fichier [Réservé aux membres club]Voir ce fichier2 178 octets
    • TestDynamique.suoTélécharger ce fichier [Réservé aux membres club]23 040 octets

Télécharger le zip

Historique

20 février 2007 07:46:37 :
Prise en compte des remarques de bidou
20 février 2007 15:53:21 :
Correction d'erreur

Commentaires et avis

signaler à un administrateur
Commentaire de Bidou le 19/02/2007 21:17:29 administrateur CS

Quelques remarques:

- Méthodes AddType(Type type) de Loads.cs
if(KeyElement.Lenght > 0) devrait plutôt être string.IsNullOrEmpty(KeyElement)

- Dans la même méthode:

if (creatable.ContainsKey(value))
{
   creatable[value] = type;
}
else
{
   creatable.Add(value, type);
}

peut-etre remplacé par

creatable[value] = type;


Si on passe une valeur inexistante dans le loader.Create, le program bug. Il faut faire un teste dans la méthode qui fait le CreateInstance (si je ne spécifie pas defaultElement, il est null => plantage)
Autre chose, 'value' est un mot clef, c'est pas recommandé de l'utiliser comme nom de variable.

Sinon pour la création des Plugins, je me demande si c'est pas plus indiqué de passer par des interfaces plutôt que Reflexion...
A voir.

signaler à un administrateur
Commentaire de Warny le 20/02/2007 07:44:35

Merci pour tes remarques, je vais mettre en place une vraie exception dans le createinstance (le plantage est voulu). Pour le test d'existence, il est indispensable.

Sinon, pour la création des plugins, il est clair que des interfaces c'est bien, mais certains objets ont parfois une activité dont on ne peut pas se passer. Même dans ce cas, il faut pouvoir charger ces objets, si on doit tout recompiler, ce n'est pas très interressant, c'est l'utilité de mon programme.
L'idée de base était de reprendre ma source client DNS et de pouvoir l'étendre à l'envie en rajoutant des extensions sans modifier le programme de base comme je dois le faire aujourd'hui.
Or, pour celle-ci, je reçois un numéro de service que je dois interpréter. Comme je ne vais pas utiliser le numéro de service pour nommer mes classes (mais bien le nom du service) il fallait que je trouve une solution... la voici.

signaler à un administrateur
Commentaire de sebmafate le 20/02/2007 09:39:57 administrateur CS

Question purement "esthétique", pourquoi écrire :
    public Loader() : this("") { ;}

Alors qu'il suffit d'écrire :
    public Loader() : this("") { }

signaler à un administrateur
Commentaire de Bidou le 20/02/2007 10:06:57 administrateur CS

"Pour le test d'existence, il est indispensable."
Non, tu peux bel et bien faire le remplacement que j'ai indiqué plus haut, simplement: creatable[value] = type;
L'indexeur se charge de tout...

signaler à un administrateur
Commentaire de Warny le 20/02/2007 11:08:01

Bidou -> Après que tu me l'ais dit... j'ai testé, il est indispensable, si je n'utilise pas ces lignes de code l'objet n'est pas integré à ma collection.

signaler à un administrateur
Commentaire de Bidou le 20/02/2007 11:37:56 administrateur CS

Tu fais très certainement une erreur. Pour t'en rendre compte, tu peux donner un coup de Reflector. Pour l'indexeur tu trouves:

public void set_Item(TKey key, TValue value)
{
    this.Insert(key, value, false);
}


signaler à un administrateur
Commentaire de Warny le 20/02/2007 14:08:36

Je ne fais pas d'erreur. La méthode Insert existe sur la classe List et pas sur la classe Dictionary.

signaler à un administrateur
Commentaire de Bidou le 20/02/2007 14:35:32 administrateur CS

Mais noooooon, Insert est une méthode privée du Dictionnary, utilisée (entre autre) par l'indexeur.
Pour te convaincre que l'indexeur ajoute bien l'élément dans le dictionary, créer une application console et met ceci dedans :

            Dictionary<int, string> dic = new Dictionary<int, string>();
            dic[1] = "Okay";        // Count 1  1-Okay
            dic[2] = "Salut";       // Count 2  1-Okay 2-Salut
            dic[2] = "Teste";       // Count 2  1-Okay 2-Teste

signaler à un administrateur
Commentaire de Warny le 20/02/2007 15:54:47

Oups, tu as raison, l'erreur venait d'ailleurs dans mon code, c'est corrigé.

signaler à un administrateur
Commentaire de sebmafate le 20/02/2007 15:56:00 administrateur CS

:)

Bidou : 1, Warny : 0

J'adore ;)

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Declaration dynamique d'une classe [ par Barz ] Comment par code peut-on executer une méthode d'une classe en dynamique, c'est à dire en ayant que une chaine correspondant au nom de la classe et une litse de fichiers dynamique [ par denistheisen ] Bonjour, Je suis a la recherche d'un javascript qui me permettrait de generer une liste dymanique de fichiers se trouvant dans un de mes repertoires e Création d'un tableau dynamique HTML par le code... [ par pchanet ] Bonjour à tous,Je suis en train de développer la gestion d'une table HTML (type &lt;table&gt;...&lt;/table&gt;) en dynamique à partir de la page de co Génération dynamique de windows.form en C# [ par Thanos_the_yopper ] Bonjour,je suis en train de faire une appli qui, en fonction du contenu d'un fichier XML construit dynamiquement une fenetre windows avec des champs d Objet dynamique .net. [ par jonguerre ] Bonjour,Petite question je crée 2 objets Panel (panel1,panel2);panel1 = new System.Windows.Forms.Panel();panel2 = new System.Windows.Forms.Panel();J'a Tableau dynamique [ par redpooka ] Comment faire un tableau à 2 dimension dynamique ?Avec les collections arraylist, on peut faire un mais c'est juste avec une dimension.tableau du styl Faire une zone de texte dynamique [ par typhoonx ] Bonjour,Je suis en train de programmer une application de compression (dll dévelopée en C) et interface C#.Je voudrais faire une zone de texte dans la site Dynamique [ par Gina78 ] Bonjour,Je voudrais juste savoir les premières étapes pour creer un site DynamiqueMerci générer un contrôle ( bouton) dynamique en c# [ par poelvo ] Je voudrais créer des boutons à partir d'une liste d'objet d'une base de données, je n'aurai donc jamais le même nombre de boutons. Je ne sais donc pa Nom dynamique de fichier [ par Sunnyprog ] Sunnyprogfont=GeorgiaBonjour tt le monde !je voudrais savoir comment faire pour nommer un fichier de telle manière qu'il ait pour nom le contenu d'une


Nos sponsors

Sondage...

CalendriCode

Décembre 2008
LMMJVSD
1234567
891011121314
15161718192021
22232425262728
293031    

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :