Le mécanisme de réflexion fourni par .NET peut facilement charger des plug-ins. Cet article fournit une méthode permettant de charger de manière flexible et correcte les plug-ins requis.
Dans .NET, un nom de type complet a le format « nom de type, nom d'assembly ».
Par exemple : « System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ».
Le nom du type est : System.Configuration.NameValueSectionHandler, qui est le nom de type complet avec l'espace de noms.
Vous pouvez également obtenir le FullName en utilisant le type.
Par exemple : string typeName = typeof(NameValueSectionHandler).FullName;
Le nom de l'assembly est : "Système, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
L'assembly est nommé System et le système adapte automatiquement son extension (telle que System.dll ou System.exe) ;
Version, Culture et PublicKeyToken correspondent à la version spécifique, au contexte culturel et à la signature de l'assembly. Il n'y a pas d'exigences spécifiques et celles-ci peuvent être omises.
Nous pouvons charger dynamiquement un type requis en fonction du nom du type. comme:
string typeName = "System.Configuration.NameValueSectionHandler, System";
Tapez t = Type.GetType(typeName);
Objet obj = Activator.CreateInstance(t);
//ou
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
À ce stade, obj est l’instance de type requise.
Habituellement, les plug-ins sont des classes qui doivent implémenter certaines interfaces. Par conséquent, avant de charger un plug-in, vous devez déterminer si le type de plug-in est approprié.
Par exemple, si l’interface d’un plug-in est IPlugin, on peut l’identifier de la manière suivante :
chaîne interfaceName = typeof(IPlugin).FullName;
string typeName = "Muf.MyPlugin, MyPlugin" ;
Tapez t = Type.GetType(typeName);
si ( t == nul
|| !t.IsClass
|| !t.IsPublic
|| t.GetInterface(interfaceName) == null)
{
return null ; // Pas le plugin requis
}
En résumant le code ci-dessus, nous pouvons créer un code général pour charger les plug-ins :
/**//// <résumé>
/// Charger et créer dynamiquement un type possédant l'interface spécifiée
/// </summary>
/// <param name="className">Nom du type</param>
/// <param name="interfaceName">Nom de l'interface spécifié</param>
/// <param name="param">Spécifiez les paramètres du constructeur (un tableau nul ou vide signifie appeler le constructeur par défaut)</param>
/// <returns>Renvoie le type créé (null signifie que le type ne peut pas être créé ou introuvable)</returns>
objet statique public LoadObject (string className, string interfaceName, object[] param)
{
essayer
{
Tapez t = Type.GetType(className);
si ( t == nul
|| !t.IsClass
|| !t.IsPublic
|| t.IsAbstrait
|| t.GetInterface(interfaceName) == null)
{
renvoie null ;
}
objet o = Activator.CreateInstance(t, param);
si( o == nul )
{
renvoie null ;
}
revenir o;
}
attraper(Exception ex)
{
renvoie null ;
}
}
Plus tard, nous pourrons utiliser LoadObject pour charger tous les plug-ins requis.
Les plug-ins sont généralement placés dans des fichiers de configuration et lus par le programme :
Exemples de fichiers de configuration (voir mes essais connexes sur l'utilisation des fichiers de configuration) :
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="Channels" type="Vmp.Configuration.ChannelsSectionHandler, Communication" />
</configSections>
<Canaux>
<canal
ChannelType="Vmp.Communication.TcpChannel, Communication"
TraceFile="d:logchannel1.log"
Port="2020" MaxConnections="300" BufferSize="2048"
/>
</Canaux>
</configuration>
Exemple de code :
private ArrayListchannelsList = new ArrayList();
private LoadChannels()
{
ArrayList canauxConfig = (ArrayList)ConfigurationSettings.GetConfig( "Canaux" );
foreach (configuration de la table de hachage dans ChannelsConfig)
{
chaîne canalType = (chaîne) config["ChannelType"];
canal IChannel = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, nouvel objet[]{config});
si (canal == nul)
continuer ;
channelsList.Add(channel);
}
Vous pouvez également parcourir le répertoire de plug-ins spécifié et charger tous les plug-ins qui répondent aux exigences, par exemple :
public IPlugin[] LoadAllPlugIn(string pluginDir)
{
//Définit le répertoire du plugin par défaut
si (pluginDir == null || pluginDir == "")
pluginDir = "./PlugIns";
// Récupère le nom de l'interface du plug-in
string interfaceName = typeof(IPlugin).FullName;
// Tableau utilisé pour stocker les plug-ins
ArrayList arr = new ArrayList();
// Parcourez le répertoire du plug-in (en supposant que le plug-in est un fichier dll)
foreach (fichier de chaîne dans Directory.GetFiles (pluginDir, "*.dll"))
{
//Charge le fichier du plug-in
Assemblage asm = Assembly.LoadFile(file);
// Parcours des classes de plug-in exportées
foreach (Tapez t dans asm.GetExportedTypes())
{
//Charge le plug-in Si le plug-in n'est pas conforme à l'interface spécifiée, renvoie null.
Plugin IPlugin = LoadObject(t.FullName, interfaceName, null) comme IPlugin
if(plugin != null)
arr.Add(plugin);
}
}
// Retour au plugin
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}