Dynamic Link Library

Bonjour à tous, je me présente, je m’appelle Damien, développeur chez Webwag, aujourd’hui nous allons voir ensemble comment charger dynamiquement des bibliothèques dynamiquement, problématique rencontré dans le cadre d’un projet en C# pour Windows.

Introduction

Le chargement de bibliothèques dynamiques permet d’accroître considérablement la flexibilité d’une application. Des nouvelles fonctionnalités peuvent être ajoutées sous forme de modules sans qu’il soit nécessaire de recompiler la totalité de l’application.

Comment cela fonctionne

Le chargement de façon dynamique des bibliothèques n’est possible que si les deux parties implémentent une interface commune afin de pouvoir communiquer. Le contenu de cette interface, ne peut pas être modifier sans que l’application ainsi que l’ensemble des modules soit complètement recompilés.

Interface

L’interface commune n’est pas différente d’une interface ordinaire, elle peut contenir des propriétés, des méthodes ainsi que des évents. Elle permet a l’application d’avoir un point d’accès aux futurs modules étant donné que l’application n’ aucune visibilité sur les classes implémentées dans les modules.

using System;

namespace BlogueInterface {
    public interface IPlugin {

        string Name { get; }

        event EventHandler OnExecute;

        string Execute();

    }
}

Application

L’application est le socle qui permet de charger dynamiquement les futurs modules, pour les utiliser via l’interface commune.

Chargement dynamique des modules :

private void LoadPlugin(string path) {
    try {
        if (PluginLoaded.Contains(path)) {
            return;
        }
        AssemblyName assemblyName = AssemblyName.GetAssemblyName(path);
        var assemblyLoaded = Assembly.Load(assemblyName);
        if (assemblyLoaded == null) {
            return;
        }
        if (!CheckInterfaceIsValid(assemblyLoaded)) {
            return;
        }
        PluginLoaded.Add(path);
        PluginLoadedName.Add(assemblyName.Name);
        //LoadResourceDependencies(assemblyLoaded);
        var types = assemblyLoaded.GetTypes().Where(type => IsInterfaceValid(type));
        if (types == null) {
            return;
        }
        foreach (var type in types) {
            if (type.IsAbstract || type.IsInterface || !type.IsVisible) {
                continue;
            }
            else {
                if (!Types.Contains(type)) {
                    Types.Add(type);
                }
            }
        }
    }
    catch (ReflectionTypeLoadException es) {
        Debug.WriteLine("Error during assembly loading " + es);
    }
    catch (Exception ex) {
        Debug.WriteLine("Error during assembly loading " + ex);
    }
}

Création des classes des modules :

Afin de créer les classes des différent modules, il est nécessaire de passer par la méthode système : Activator.CreateInstance().

public ObservableCollection<IPlugin> GetPlugins() {
    var list = new ObservableCollection<IPlugin>();

    Types.FindAll(item => typeof(IPlugin).IsAssignableFrom(item)).ForEach(item => {
        var plugin = GetClass<IPlugin>(item.FullName);
        list.Add(plugin);
    });
    return list;
}
public T GetClass<T>(string name) {
    foreach (var t in Types) {
        if (t.FullName == name && t.IsAssignableFrom(t)) {
            return (T)Activator.CreateInstance(t);
        }
    }
    throw new ArgumentException("Type not Exist");
}

Utilisation des modules :

Pour utiliser les modules il convient d’appeler la méthode Execute() définie dans l’interface IPlugin.

private void Clicked(IPlugin obj) {
    var str = obj.Execute();
    MessageBox.Show(str);
}

Module

Dans notre exemple nous allons implémenter deux modules, le premier qui affichera l’heure et le second qui donnera une température.

using BlogueInterface;
using System;

namespace PluginTime {
    public class PTime : IPlugin {
        public string Name => "Heure";

        public event EventHandler OnExecute;

        public string Execute() {
            OnExecute?.Invoke(this, null);
            return DateTime.Now.ToString();
        }
    }
}
using BlogueInterface;
using System;

namespace PluginMeteo {
    public class PMeteo : IPlugin {
        public string Name => "Météo";

        public event EventHandler OnExecute;

        public string Execute() {
            Random random = new Random();
            var result = random.Next(-10, 35);
            OnExecute?.Invoke(this, null);
            return $"{result} °C";
        }
    }
}
Articles liés
L’authentification biométrique avec TouchID et FaceID
À la découverte du RecyclerView
Refresh token
Refresh token – Android
Créer une application pour Apple TV

Laissez votre commentaire

Votre commentaire*

Votre Nom*
Votre site internet

deux + 2 =