Création dynamique d'objets

Soyez le premier à donner votre avis sur cette source.

Vue 12 641 fois - Téléchargée 722 fois

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 / Exemple :


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
}

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
4936
Date d'inscription
lundi 17 février 2003
Statut
Modérateur
Dernière intervention
14 février 2014
36
:)

Bidou : 1, Warny : 0

J'adore ;)
Messages postés
473
Date d'inscription
mercredi 7 août 2002
Statut
Membre
Dernière intervention
10 juin 2015

Oups, tu as raison, l'erreur venait d'ailleurs dans mon code, c'est corrigé.
Messages postés
5487
Date d'inscription
dimanche 4 août 2002
Statut
Modérateur
Dernière intervention
20 juin 2013
54
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 dic = new Dictionary();
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
Messages postés
473
Date d'inscription
mercredi 7 août 2002
Statut
Membre
Dernière intervention
10 juin 2015

Je ne fais pas d'erreur. La méthode Insert existe sur la classe List et pas sur la classe Dictionary.
Messages postés
5487
Date d'inscription
dimanche 4 août 2002
Statut
Modérateur
Dernière intervention
20 juin 2013
54
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);
}
Afficher les 10 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.