.NET が提供するリフレクション メカニズムにより、プラグインを簡単にロードできます。この記事では、必要なプラグインを柔軟かつ正確にロードできる方法を提供します。
.NET では、完全な型名の形式は「型名、アセンブリ名」になります。
例: 「System.Configuration.NameValueSectionHandler、System、Version=1.0.3300.0、Culture=neutral、PublicKeyToken=b77a5c561934e089」。
型名は System.Configuration.NameValueSectionHandler で、名前空間を含む完全な型名です。
タイプを使用して FullName を取得することもできます。
例: string typeName = typeof(NameValueSectionHandler).FullName;
アセンブリ名は「System、Version=1.0.3300.0、Culture=neutral、PublicKeyToken=b77a5c561934e089」です。
アセンブリの名前は System であり、システムはその拡張子 (System.dll や System.exe など) を自動的に調整します。
Version、Culture、および PublicKeyToken は、アセンブリの特定のバージョン、文化的背景、および署名です。これらは省略できます。
型の名前に基づいて必要な型を動的にロードできます。のように:
string typeName = "System.Configuration.NameValueSectionHandler, System";
タイプ t = Type.GetType(typeName);
オブジェクト obj = Activator.CreateInstance(t);
//または
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
この時点では、obj が必須の型インスタンスです。
通常、プラグインは特定のインターフェイスを実装する必要があるクラスです。したがって、プラグインをロードする前に、プラグインのタイプが適切かどうかを判断する必要があります。
たとえば、プラグインのインターフェイスが IPlugin の場合、次の方法で識別できます。
文字列インターフェイス名 = typeof(IPlugin).FullName;
文字列 typeName = "Muf.MyPlugin, MyPlugin";
タイプ t = Type.GetType(typeName);
if ( t == null
|| !t.IsClass
|| !t.Isパブリック
|| t.GetInterface(インターフェイス名) == null)
{
return null; // 必要なプラグインではありません。
}
上記のコードを要約すると、プラグインをロードするための一般的なコードを作成できます。
/**//// <概要>
/// 指定されたインターフェイスを持つ型を動的にロードして作成します
/// </概要>
/// <param name="className">型名</param>
/// <param name="interfaceName">指定されたインターフェイス名</param>
/// <param name="param">コンストラクターのパラメーターを指定します (null または空の配列は、デフォルトのコンストラクターを呼び出すことを意味します)</param>
/// <returns>作成された型を返します (null は、型が作成できないか、見つからないことを意味します)</returns>
パブリック静的オブジェクト LoadObject(文字列クラス名、文字列インターフェイス名、オブジェクト[]パラメータ)
{
試す
{
タイプ t = Type.GetType(クラス名);
if ( t == null
|| !t.IsClass
|| !t.Isパブリック
|| t.IsAbstract
|| t.GetInterface(インターフェイス名) == null)
{
null を返します。
オブジェクト
o = Activator.CreateInstance(t, param);
if( o == null )
{
null を返します。
}
を返します。
}
catch(例外例)
{
null を返します。
}
}
後で、LoadObject を使用して必要なプラグインをロードできます。
プラグインは通常、設定ファイルに配置され、プログラムによって読み取られます。
設定ファイルの例 (設定ファイルの使用については、私の関連エッセイを参照してください):
<?xml version="1.0" encoding="utf-8" ?>
<構成>
<configセクション>
<section name="Channels" type="Vmp.Configuration.ChannelsSectionHandler、通信" />
</configセクション>
<チャンネル>
<チャンネル
ChannelType="Vmp.Communication.TcpChannel、通信"
TraceFile="d:logchannel1.log"
Port="2020" MaxConnections="300" BufferSize="2048"
/>
</チャンネル>
</設定>
コード例:
private ArrayList ChannelsList = new ArrayList()
;
{
ArrayList ChannelsConfig = (ArrayList)ConfigurationSettings.GetConfig( "Channels" );
foreach(channelsConfig のハッシュテーブル設定)
{
string channelType = (文字列) config["ChannelType"];
IChannel チャネル = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, new object[]{config});
if(チャンネル == null)
続行;
チャネルリスト.Add(チャネル);
指定したプラグイン ディレクトリをたどって、要件を満たすすべてのプラグインをロードすることもできます。例:
public
IPlugin[] LoadAllPlugIn(string pluginDir)
{
// デフォルトのプラグインディレクトリを設定します
if(pluginDir == null || pluginDir == "")
pluginDir = "./PlugIns";
// プラグインインターフェース名を取得します。
stringinterfaceName = typeof(IPlugin).FullName
// プラグインの保存に使用される配列
ArrayList arr = new ArrayList();
// プラグイン ディレクトリをスキャンします (プラグインが DLL ファイルであると仮定します)。
foreach(Directory.GetFiles(pluginDir, "*.dll") 内の文字列ファイル)
{
//プラグインファイルをロードする
アセンブリ asm = Assembly.LoadFile(file);
// エクスポートされたプラグイン クラスをスキャンします
foreach(asm.GetExportedTypes() に t を入力)
{
// プラグインをロードします。プラグインが指定されたインターフェイスに準拠していない場合は、null を返します。
IPlugin プラグイン = LoadObject(t.FullName, インターフェース名, null) as IPlugin
;
arr.Add(プラグイン);
}
}
// プラグインに戻ります
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}