型の解決

今日のネタ元


(別にkazuya氏のやり方を否定するとかそういうのではなく、".NETの型の解決方法"というネタで書きたかったので。)

Javaを扱ってきてその後.NETに移行した、又はJavaと.NETを並行して使用しているデベロッパであれば.NETにおける型名から型の解決がJavaのようには一筋縄で行かないということに一度ははまるのではないでしょうか。.NETの場合は型をロードするためのアセンブリを明示的に指定しなくてはならないケースがありますのでJavaのように検索パス上にあるjarファイルを単純に探索して型を解決する訳にはいかないのです。

この件に関して私が一番気に入っているのはSpring.NETの手法です。最近のSpring.NETのソースを見ていないので最新のバージョンがどのような作りになっているかは解りませんがその手順としては

1.型名を文字列で取得する
2.型名にアセンブリ名(厳密名)が指定されていればそれを分離する
3.アセンブリ名が正しければアセンブリをロードする
4.アセンブリを元に型名から型をロードする
5.型名のクラス名がいわゆる"エイリアス名"(例 Stringのエイリアスはstring)であれば正式名に変換して4.同様にロードする

です。いわゆるTypeResolverというやつですね。Spring.NETのコアパッケージに同名のクラスがあったと思います。ただし私が参考にしたビルドは一点気に入らない、というか.NETとして基本的にはやってはいけないことをしているのでそのままは使用していません。
それは手順で言うと3.のアセンブリのロードで

Assembly ass = Assembly.LoadWithPartialName (アセンブリ名(部分名も可能));

とLoadWithPartialNameメソッドを使用している部分です。このメソッドは.NET2.0では既にObsoleteになっていますが何故使ってはいけないかは.NETがアセンブリを一意に識別するメカニズムや同じ名前のアセンブリがサイドバイサイドで同居できる.NETの特徴をご存じの方であれば理解して頂けると思います。

この機構を用いている拙作のDIContainer経由でSystem.Data.IDataAdapter型を使用したコンポーネントの型名の記述例は

 

と、このようにアセンブリの厳密名を記述することが必要になります。冗長ですがLoadWithPartialNameを廃止した場合はこのように厳密な名前でアセンブリを指定する必要があります。
また、このような型の解決は結構重い処理になる場合を考慮しているのかSpring.NETはTypeResolverを拡張したCachedTypeResolverというクラスも実装しておりこちらは名前の通り一度解決した型をキャッシュしており次回からは型解決に時間的なコストをかけない作りになっています。