AOPとPostSharpでの私の経験

むかしむかし、私はPostSharpを非常によく研究し、開発目的で使用し始めました。 私はこのトピックに関するスクリーンキャストといくつかの記事を書くことさえできました。 残念ながら、PostSharpを使用した後、「どうやって?」というトピックに関するコミュニティからの定期的な問い合わせの理由で、私は後でまったく解決しませんでした。 なぜ?」、私はすべてのiにドットを付けるためにこの投稿を書くことにしました。



ネズミ捕りの無料チーズ



PostSharpでは、ILを書き換えることにより、既存のコードに機能を組み込むことができます。 この考えは新しいものではなく、ILDASMを実行し、ILで何かを変更してからILASMを実行するMSBuild-thタスクを作成することです。タスクは非常に簡単です。 かつては、アセンブリから難読化ツールからメタデータを削除するためにそれを行いました。 (なぜ難読化者がクラッカーを意図的に使用したのかを正確に伝えることで意図的にクラッカーを支援する理由はまだ謎です。)



PostSharpの本質は、たとえばメソッドを宣言的に取得してマークすることができ、各呼び出しが個別のスレッドで発生することを示すことです。



[WorkerThread] public void MyMethod() { ⋮ }
      
      





ポストコンパイル中のPostSharpはこのメソッドを取得して書き換え、単純なメソッド呼び出しをTask.Factory.StartNew(() => { /* */ });



に置き換えTask.Factory.StartNew(() => { /* */ });



。 それはよさそうだし、正直なところ、それは動作します。



しかし、多くの問題があります。 たとえば、このようなコードは管理が困難です。 つまり、別のスレッドでクラスAのメソッドのみが実行され、クラスBのメソッドがブロックされるようになったことを突然言うことはできません。 さらに、APIのユーザーにメソッドが非標準の動作を実装していることを明確に説明することはできません。メソッドはその上で非同期呼び出しブロックし、書き込むと考え続けます。



ドキュメンテーションに関しては、彼らは私と議論することができます-彼らは属性が存在するので、すべてが誰にでも明らかであるべきだと言います。 しかし、ここでも、すべてがそれほど単純ではありません。たとえば、コンパイル後に属性がまったく存在しないことが断固として嫌いです。 そして、これはPostSharpの問題でした-彼はライブラリを彼と一緒にドラッグしようとしましたが、質問に対する合理的なアプローチは、良い方法ではライブラリが必要ないことを示唆しています ILのローカル書き換えがあり、それだけです。



中毒性の効果



[NotifyPropertyChanged]



属性でマークされた巨大なクラスがありました-あなたは彼が何をしていたか既に理解していると思います。 そして、すべてが良さそうに見えますが、実際にはいくつかのことが私を悩ませました。



まず、アスペクトを介してINotifyPropertyChangedを実装するためのコードは驚くべきものでした。非常に複雑で読みにくいため、必要なときにでも触るのが怖かったです。



第二に、オブジェクト自体はコンパイル段階でINotifyPropertyChanged



を実装しなかったため、このインターフェイスへのアクセスは二重キャストによって偽造する必要がありました。



第三に、属性アプローチはオールオアナッシングでした。 たとえば、読み取り/書き込みプロパティの通知を受け取ることができますが、プロパティを変更してそれ依存する読み取り専用プロパティでNotifyPropertyChanged()



を生成したい場合 、問題が発生しました。



その結果、私は簡単なことを行いました。プロジェクトからPostSharpを削除し、 ReSharperを介してINPCを実装しました 。 言い換えれば、コードを作成するプロセスを愚かに自動化し、すべてのプロパティに従って実行し、特別なものが必要なコードを手動で修正しました。



代替案?



ILを手動で書き換えるよりも優れているように思えます。 私にとって理想的なのは、コンパイラオブジェクトモデルを使用して構造を操作することです。 実際、コンパイラが拡張するアプローチ。 Booプログラミング言語では、Nemerleもこれを行うことができますが、C#5については、誰も保証できません。次のバージョンでメタプログラミングメカニズムがどのようになるかはわかりません。



別のオプションはコード生成です。 その利点は、少なくとも何が起こっているのかを見ることができることです。 ビルド後のマジックなしでコードをコンパイルするだけです。 当然、コード生成は、ReSharperに組み込まれているような何らかの種類のパーサーを使用する場合に最適に機能します。 ReSharperのAPIを使用すると、コード操作に関して非常にクレイジーなことができます。 たとえば、従属変数の通知の問題は、独立したデーモン(アナライザー)のレベルで簡単に解決されます。このデーモンは、依存関係をステップスルーし、何をどこに追加するかを教えてくれます。



3番目のオプションは、DSLを作成することです。 タスクが単純なC#に当てはまらない場合、おそらくその中に場所がありません。 同じF#または他の言語でDSLを記述するか、たとえばMPSを使用してこのDSLを設計し、そこから何かを生成します。 はい、これは異なる角度からのみの同じコード生成ですが、少なくともこのアプローチは誤解を招きにくいです。特定の言語の制限に互換性のない概念を詰め込もうとはしません。



以上です。 AOP / PostSharpに対する私の態度は、私の個人的な意見であることに注意してください。 すべてがあなたのために働く場合-それは超、それについて書いてください! ■



All Articles