Der von .NET bereitgestellte Reflexionsmechanismus kann Plug-Ins problemlos laden. Dieser Artikel stellt eine Methode bereit, mit der die erforderlichen Plug-Ins flexibel und korrekt geladen werden können.
In .NET hat ein vollständiger Typname das Format „Typname, Assemblyname“.
Beispiel: „System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089“.
Der Typname lautet: System.Configuration.NameValueSectionHandler, was der vollständige Typname mit Namespace ist.
Sie können den vollständigen Namen auch über den Typ abrufen.
Beispiel: string typeName = typeof(NameValueSectionHandler).FullName;
Der Assemblyname lautet: „System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089“,
Die Assembly heißt System und das System passt ihre Erweiterung (z. B. System.dll oder System.exe) automatisch an.
Version, Kultur und PublicKeyToken sind die spezifische Version, der kulturelle Hintergrund und die Signatur der Assembly. Es gibt keine spezifischen Anforderungen und diese können weggelassen werden.
Wir können einen erforderlichen Typ basierend auf dem Namen des Typs dynamisch laden. wie:
string typeName = "System.Configuration.NameValueSectionHandler, System";
Typ t = Type.GetType(typeName);
Object obj = Activator.CreateInstance(t);
//oder
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
Zu diesem Zeitpunkt ist obj die erforderliche Typinstanz.
Normalerweise sind Plug-Ins Klassen, die bestimmte Schnittstellen implementieren müssen. Daher müssen Sie vor dem Laden eines Plug-Ins feststellen, ob der Plug-In-Typ geeignet ist.
Wenn die Schnittstelle eines Plug-Ins beispielsweise IPlugin ist, können wir es auf folgende Weise identifizieren:
string interfaceName = typeof(IPlugin).FullName;
string typeName = "Muf.MyPlugin, MyPlugin";
Typ t = Type.GetType(typeName);
if ( t == null
||. !t.IsClass
||. !t.IsPublic
||. t.GetInterface(interfaceName) == null)
{
return null; // Nicht das erforderliche Plugin
}
Wenn wir den obigen Code zusammenfassen, können wir einen allgemeinen Code zum Laden von Plug-Ins erstellen:
/**//// <Zusammenfassung>
/// Dynamisch einen Typ laden und erstellen, der über die angegebene Schnittstelle verfügt
/// </summary>
/// <param name="className">Typname</param>
/// <param name="interfaceName">Angegebener Schnittstellenname</param>
/// <param name="param">Geben Sie die Parameter des Konstruktors an (null oder leeres Array bedeutet, dass der Standardkonstruktor aufgerufen wird)</param>
/// <returns>Gibt den erstellten Typ zurück (null bedeutet, dass der Typ nicht erstellt oder nicht gefunden werden kann)</returns>
öffentliches statisches Objekt LoadObject(string className, string interfaceName, object[] param)
{
versuchen
{
Typ t = Type.GetType(className);
if ( t == null
||. !t.IsClass
||. !t.IsPublic
||. t.IsAbstract
||. t.GetInterface(interfaceName) == null)
{
null zurückgeben;
}
object o = Activator.CreateInstance(t, param);
if( o == null )
{
null zurückgeben;
}
Rückkehr o;
}
Catch (Ausnahme ex)
{
null zurückgeben;
}
}
Später können wir LoadObject verwenden, um alle erforderlichen Plug-Ins zu laden.
Plug-Ins werden im Allgemeinen in Konfigurationsdateien abgelegt und vom Programm gelesen:
Beispiele für Konfigurationsdateien (siehe meine entsprechenden Aufsätze zur Verwendung von Konfigurationsdateien):
<?xml version="1.0" binding="utf-8" ?>
<Konfiguration>
<configSections>
<section name="Channels" type="Vmp.Configuration.ChannelsSectionHandler, Communication" />
</configSections>
<Kanäle>
<Kanal
ChannelType="Vmp.Communication.TcpChannel, Kommunikation"
TraceFile="d:logchannel1.log"
Port="2020" MaxConnections="300" BufferSize="2048"
/>
</Kanäle>
</configuration>
Codebeispiel:
private ArrayListchannelsList = new ArrayList();
private LoadChannels()
{
ArrayListchannelsConfig = (ArrayList)ConfigurationSettings.GetConfig( "Channels" );
foreach (Hashtable-Konfiguration inchannelsConfig)
{
stringchannelType = (string) config["ChannelType"];
IChannelchannel = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, new object[]{config});
if(channel == null)
continue;
KanäleList.Add(Kanal);
}
Sie können auch das angegebene Plug-In-Verzeichnis durchsuchen und alle Plug-Ins laden, die die Anforderungen erfüllen, zum Beispiel:
public IPlugin[] LoadAllPlugIn(stringpluginDir)
{
//Legen Sie das Standard-Plugin-Verzeichnis fest
if(pluginDir == null ||pluginDir == "")
plugDir = "./PlugIns";
// Den Namen der Plug-in-Schnittstelle abrufen
string interfaceName = typeof(IPlugin).FullName;
// Array zum Speichern von Plug-Ins
ArrayList arr = new ArrayList();
// Durchsuchen Sie das Plug-in-Verzeichnis (vorausgesetzt, das Plug-in ist eine DLL-Datei)
foreach(String-Datei in Directory.GetFiles(pluginDir, „*.dll“))
{
//Laden Sie die Plug-In-Datei
Assembly asm = Assembly.LoadFile(file);
// Durchlaufe die exportierten Plug-in-Klassen
foreach(Geben Sie t in asm.GetExportedTypes() ein)
{
//Laden Sie das Plug-in. Wenn das Plug-in nicht der angegebenen Schnittstelle entspricht, geben Sie null zurück
IPlugin-Plugin = LoadObject(t.FullName, interfaceName, null) as IPlugin;
if(plugin != null)
arr.Add(plugin);
}
}
// Zurück zum Plugin
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}