Castleライブラリについて少しだけ調べてみた
はじめに
前回記事の続きです。
https://qiita.com/mngreen/items/35e45714b1e7540ffd62
C#のテストライブラリであるMoqは、インターフェイスをジェネリックで定義し、その後に振る舞いを注入できます。
しかし、どのような仕組みでそのようなことができるのか皆目見当がつかないため、利用ライブラリを遡って調べているという状況です。
Avatarが参照しているライブラリがCastle.Coreライブラリでしたので、こちらについて調べて分かったポイントを次章以降に記します。
調べている途中にCastle.Coreライブラリの製作者が詳細に説明されているサイトがありましたので、より具体的に確認したい方は以下を参照ください。
https://kozmic.net/dynamic-proxy-tutorial/
Castle.Coreとは
Castleという名前自体はプロジェクト?の名前でした。以下、プロジェクトのURLです。
http://www.castleproject.org/
Castle.Coreライブラリでは、以下を提供すると述べられています。
Castle Core は、ロギング サービスを含む一般的な Castle Project の抽象化を提供します。また、軽量のランタイム プロキシ ジェネレータであるCastle DynamicProxyとCastle DictionaryAdapterも備えています。
DynamicProxyについては、プロジェクトのサイトでも紹介されているページがあります。
http://www.castleproject.org/projects/dynamicproxy/
ドキュメントのリンクを辿ると、以下に行き着きます。
Moq以外にも多くのOSSで利用されていることが分かります。
https://github.com/castleproject/Core/blob/master/docs/dynamicproxy.md
上記のページにCastle DynamicProxyの導入へのリンクがありましたので、その内容についてみていきます。
Castle DynamicProxyとは
以下のページが、Castle DynamicProxyの導入となっています。
https://github.com/castleproject/Core/blob/master/docs/dynamicproxy-introduction.md
イントロダクションでは、もともとCLRにもプロキシの実装としてMarshalByRefObjectがあるものの、拡張性が乏しかったこと、より多くの機能を提供するために開発されたプロキシのライブラリであることが述べられています。
上記のページをKinds of proxy objects → Tutorial on DynamicProxy discussing with examples all kinds of proxiesとジャンプすると、DynamicProxyへのリンクがあります。次章では、このサイトの中での重要ポイントをピックアップして、DynamicProxyの仕組みを確認します。
DynamicProxyでインターフェイス指定のみでインスタンス生成できる仕組み
DynamicProxyの考え方は、以下が参考になりました。
https://kozmic.net/2008/12/16/castle-dynamicproxy-tutorial-part-i-introduction/
実体となるメソッドが呼び出されるまでの間に、別の処理を追加できるようにするInterceptorを呼び出されるようにするところがポイントかと思います。
ただ、それはMoqでインターフェイス指定するだけでモックのインスタンスが取得できる理由にはいまいちなっていない気がします。
そこで、ブログの他ページを参照したところ、以下の記事にヒットしました。
https://kozmic.net/2009/03/20/castle-dynamic-proxy-tutorial-part-viii-interface-proxy-without-target/
正直まだわかってはいませんが、ProxyGenerator.CreateInterfaceProxyWithoutTargetメソッドがキーになりそうなことが分かりました。
GitHubで検索すると、以下のURLにたどり着きます。
https://github.com/castleproject/Core/blob/c6d7a165ac3050ebfc70debabe52ee6624a97bdf/src/Castle.Core/DynamicProxy/ProxyGenerator.cs#L30
そして、実際にインスタンスを返すのは以下のメソッドです。
https://github.com/castleproject/Core/blob/c6d7a165ac3050ebfc70debabe52ee6624a97bdf/src/Castle.Core/DynamicProxy/ProxyGenerator.cs#L814
具体的には、
- インターフェイスが指定されていることを検証
-
ProxyGenerator.CreateInterfaceProxyTypeWithoutTargetメソッドを呼び出し、新しいタイプを生成する(!?)
- その内部では、特に指定しない場合DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTargetメソッドが呼び出されている
- InterfaceProxyWithoutTargetGenerator の基底クラスであるBaseInterfaceProxyGenerator.GenerateTypeメソッドがその実処理を行う
- 生成したタイプに引数を渡し、インスタンス生成する
おわりに
正直不明点がまだまだ残っていますが、ざっくり概要は掴めてきた感じがします。
次回は、指定したインターフェイスを実装するタイプを動的に生成する仕組みを調べてみようと思います。