高見知英のかいはつにっし(β)

高見知英のアプリケーション開発日誌 のほか、地域活動などの活動報告ブログ。

Type.IsSubclassOfを使うときの注意

C#でプラグインを読み込んで使うタイプのソフトを作るときは、プラグインのベースとなるクラスをDLLに作って、そのクラスを各プラグインに継承させるようにするといいです。

  • 大元のDLL(base.dllとします)
    • プラグインのベースとなるクラス(classBaseとします)
  • プラグインDLL(plugin.dllとします)
    • 参照設定
      • base.dll
    • プラグインに使いたいクラス(classBaseを継承。classPluginとします。)
  • メインプロジェクト(main.exeとします)
    • 参照設定
      • base.dll
    • プラグインを使用するコード

このような感じ。うーん、何となく見づらいですが、わかるでしょうか?

    public static Type[] GetTypes(Type typeOf, Assembly[] assemblies)
    {
      ArrayList types = new ArrayList();
      foreach(Assembly asm in assemblies)
      {
        foreach(Type type in asm.GetTypes())
        {
          if(type.IsSubclassOf(typeOf)) types.Add(type);
        }
      }
      return (Type[])types.ToArray(typeof(Type));
    }

すると、上のような感じで、任意のクラスのサブクラスのみを抽出することができます(上のままだとAbstractクラスも読み込んでしまうので、必要に応じて工夫してください)、作成中のChie.Reflection.dllにも収録されているコードです。
さて、しかし、plugin.dllを、専用のディレクトリに配置する(.\plugins\とします)ことになっている場合、注意が必要です。
plugin.dllの参照設定のプロパティにて「ローカルコピー」がTrueになっていると、base.dllがpluginsディレクトリにもコピーされるため、base.dllが二つ存在することになってしまいます。

  • base.dll
  • main.exe
  • plugins\plugin.dll
  • plugins\base.dll(plugin.dllが持ってきたローカルコピー)

上のようになると、plugin.dll内に入っているクラスが自分の持ってきたローカルコピーに入っているクラスを継承してしまうため、main.exeからtypeof(classPlugin).IsSubclassOf(typeof(classBase))としても、falseと判定されてしまいます。plugin.dllでbase.dllのローカルコピーを行わないようにすれば、当然先のコードは期待通りtrueを返します。


ということで、プラグインDLLを作るときは、大元のクラスが入ったDLLをローカルコピーしないようにしましょうね というお話。参照設定のプロパティなんてわたしは一度も見たことがなかったので、要注意です。


なお、取得したTypeはActivator.CreateInstanceでインスタンス化しましょう(別に方法が用意してあるならそれでも良いですが)。