単純派生したクラスを動的に生成する(3)

AppDomain境界を越えて動的に生成した型にアクセスする場合、例えば.NET Remoting等では他のAppDomainが生成した型にアクセスすることは出来ないので、生成した型が属するアセンブリを保存する必要が出てくる。

これだが、動的に生成したアセンブリを無理に保存しなくても、アセンブリの解決は可能であることが判明した。関連した記述は自分の日記だ。

BinaryFormatter#Deserialize(4)(標題とはあまり関係ないが)

元々自分の備忘録になればと思って始めた日記だったが、このように過去のエントリにトラックバックを打てると、充実感がある。
話を元に戻そう。つまりは別なAppDomainで生成された動的な型が属する動的なアセンブリへのアクセスが失敗しているのであれば、リンクされたエントリにあるように、AssemblyResolveイベントが発生するはずである。
AssemblyResolveイベントはその引数に解決できなかったアセンブリ名がNameプロパティとしてセットされてくるので、動的な型が生成される度に同イベントを追加して、内部でアセンブリ名が合致したら、型を生成するために使ったAssemblyBuilder(AssemblyBuilderはAssemblyのサブクラスである)を返すようにしてやれば良い。

//前回書いた、CreateDynamicDelivedClassメソッドの末尾を抜粋

    if (saveAssembly) asmBuild.Save(asmName.Name + ".dll");
    //アセンブリ解決イベントを追加
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(
        delegate(object sender, ResolveEventArgs args)
        {
            if (args.Name.Equals(asmBuild.FullName))
            {
                return asmBuild;
            }
            else
            {
                return null;
            }

        });
    return newType;

AssemblyBuilderを静的なメンバにすることなしにイベントを書けるのは、匿名デリゲートさま様だ。
今回はさほど多くの型を生成する予定が無いので、このようにデリゲート(イベント)にしているが、数が多くなるのであれば、動的に型を生成する度に、型名とアセンブリをIDictionary等の辞書にキャッシュするのが良いだろう。

これで動的なアセンブリを物理ファイルに保存することなしに、別AppDomainからもこの型にアクセスできるようになった。ただし、これも以前のエントリで言及したと思うが、動的なアセンブリを物理的に保存しないということは、アセンブリにディジタル署名が出来ないことを意味するため、厳密な名前は機能しなくなることに注意が必要だろう。

AssemblyBuilder クラス