Pluginの実装3
IWidgetの実装クラスの検索は、WidgetPluginクラスのstaticメソッドとして実装しています。
クラスの検索にはアセンブリをロードする必要がありますが、使用しないアセンブリは検索処理後にはアンロードしたいところです。
アンロードはアプリケーションドメイン単位でしかできないので、ここでは検索処理専用のアプリケーションドメインを作成して、その中で処理を行う事にします。
呼び出し側アプリケーションで実行されるコードはこんな感じです。
public static WidgetPlugin[] FindWidget(string floder) { WidgetPlugin[] widgets = null; AppDomain outer = null; try { outer = AppDomain.CreateDomain( "FindWidget" ); outer.SetData( "FindWidgetOnOuterDomain_Param", floder ); outer.DoCallBack( new CrossAppDomainDelegate( WidgetPlugin.FindWidgetOnOuterDomain ) ); widgets = (WidgetPlugin[])outer.GetData( "FindWidgetOnOuterDomain_Result" ); } catch { } finally { if ( outer != null ) { AppDomain.Unload( outer ); } } return ( widgets ); }
検索用アプリケーションドメインを作成して、AppDomain.DoCallBack()によりそのアプリケーションドメインで処理を実行します。
アプリケーションドメインを越えるパラメータのやりとりについては、AppDomain.SetData()、AppDomain.GetData()を使用します。
で、以下がクロスドメインで実行される検索処理になります。
private static void FindWidgetOnOuterDomain() { string folder = (string)AppDomain.CurrentDomain.GetData( "FindWidgetOnOuterDomain_Param" ); string[] dlls = Directory.GetFiles( folder, "*.dll" ); List<WidgetPlugin> list = new List<WidgetPlugin>(); Type widgetType = typeof( IWidget ); foreach( string dll in dlls ) { try { Assembly assembly = Assembly.LoadFrom( dll ); foreach( Type t in assembly.GetExportedTypes() ) { if ( ( widgetType.IsAssignableFrom( t ) == true ) && ( t.IsClass == true ) && ( t.IsAbstract == false ) ) { string name = t.FullName; string version = ""; string description = ""; WidgetInfoAttribute attr = (WidgetInfoAttribute)Attribute.GetCustomAttribute( t, typeof( WidgetInfoAttribute ) ); if ( attr != null ) { name = ( attr.Name != null ? attr.Name : "" ); version = ( attr.Version != null ? attr.Version : "" ); description = ( attr.Description != null ? attr.Description : "" ); } list.Add( new WidgetPlugin( dll, t.FullName, name, version, description ) ); } } } catch { } } WidgetPlugin[] widgets = list.ToArray(); AppDomain.CurrentDomain.SetData( "FindWidgetOnOuterDomain_Result", widgets ); }
指定フォルダのDLL一覧を検索して、アセンブリ中からIWidget派生なもの(ClassでAbstractじゃないもの)を探す処理になります。
該当するクラスが見つかった場合はメタ情報としてWidgetInfoAttributeを取得し、収集した情報からWidgetPlugin情報を作成しています。
#とりあえずフォルダの再帰検索は入ってません
処理結果の戻りがCollectionではなく配列なのは、オブジェクトがAppDomainを越えるためにはSerializableであるか、またはMarshalByRefObject派生である必要があるためです。
Serializableなオブジェクトはドメインを越えてコピーされますし、MarshalByRefObjectは別アプリケーションドメインからはProxy経由で参照されます。
この辺の正確なことはEssential.NETを読むといいですね。
- 作者: ドン・ボックス,クリス・セルズ,Don Box,Chris Sells,吉松史彰
- 出版社/メーカー: 日経BP社
- 発売日: 2003/06/14
- メディア: 単行本
- 購入: 10人 クリック: 203回
- この商品を含むブログ (36件) を見る
で、ここまででPluginの情報収集はできるようになったので、次はPluginのロード・アンロード処理になります。