Roslynを使用して、実際にコンパイルする前にC#コードを変更したいと思います。今のところ、次のようなものが必要です。
[MyAnotatedMethod]
public void MyMethod()
{
// method-body
}
そして、アノテーションに基づいて、メソッドの最初と最後にコードを挿入したいと思います。
私はPostSharpを知っていますが、それは私が望んでいることではありません。
これはRoslynで行うことは可能ですか?もしそうなら、例を挙げていただけますか?
ここにあなたが望むことをするための迅速で汚い方法があります。これは、上記のコメントの1つに基づいており、 SebbyLive を指しています。これは概念実証にすぎず、本番環境で使用することはしません。
基本的な考え方は、変更するプロジェクトのコンパイラを変更することです。そして、この変更されたコンパイラはコードインジェクションを行います。したがって、新しいコンパイラー(AopCompiler.exe)を作成し、それをプロジェクトのビルドツールとして設定する必要があります。
ビルドツールとしてのAopCompiler.exeの設定は簡単です。プロジェクトファイルで、次の2行を追加する必要があります。
<CscToolPath>$(SolutionDir)AopCompiler\bin\Debug</CscToolPath>
<CscToolExe>AopCompiler.exe</CscToolExe>
AopCompilerは単純なコンソールアプリケーションである必要があります。これは、コードの変更とコンパイルも行います。ソースコードを変更したくない場合は、ビルドするだけです。最も簡単な方法は、csc.exeを自分で呼び出すことです。
static void Main(string[] args)
{
var p = Process.Start(@"C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe",
string.Join(" ", args));
p.WaitForExit();
}
これをこれまでに設定すると、アスペクトを織り込むことなく、通常のビルドプロセスができます。
この時点で、args
の内容を確認すると、csc.exeのすべてのコマンドラインパラメーターを含む.RSPファイルへのファイルパスがあることがわかります。もちろん、これらのパラメータにはすべての.CSファイル名も含まれています。したがって、この.RSPファイルを解析して、コンパイルの一部であるすべての.CSファイルを見つけることができます。
C#ファイルが手元にあれば、Roslynを使用して書き換えを行うことができます。 CSharpSyntaxRewriter
には多くのチュートリアルがあります。たとえば、 ここ 、 ここ です。特定の属性をチェックするカスタムCSharpSyntaxRewriter
を記述し、見つかったメソッドの先頭にロギングを追加する必要があります。複数の出口点が存在する可能性があるため、各メソッドの最後にロギングを追加するのは少し難しいです。それらを見つけるには、制御フロー分析を使用できます。組み込みのRoslyn制御フロー分析により、目的を正確に把握できます。 ExitPoints
プロパティは、領域外の場所にジャンプする領域内のステートメントのセットを保持します。
セマンティックモデルを取得するには(そしてCFG分析を実行するには)、次のようにします。
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
var semanticModel = _compilation.GetSemanticModel(node.SyntaxTree);
// semanticModel.AnalyzeControlFlow(node.Block)
return node;
}
最後に、各入力ファイルであるAopCompilerを処理するには、ツリーのルートでリライターのVisit
メソッドを呼び出すだけです。これにより、変更されたツリーが生成され、ファイルに書き出すことができます。 (元のファイルを変更するか、結果を新しいファイルに書き込んで、それに応じて.RSPファイルを変更することができます。)
完全に機能するソリューションを提供していないことをお詫びしますが、これで十分に始めることができます。
私のコメントで指摘したように、それは現在利用できません。示されているAOP手法を使用して何かを組み合わせることができますが ここ と Roslyn Scripting API を使用して、非常に柔軟なソリューションを提供します。
現時点での正解は、Roslynチームがそれをサポートするためのオープンな提案/問題を抱えているということです。オープンソースに参加している.NetFoundationとMicrosoftのおかげで、この機能の開発についてここで読むことができます。
アノテーションを使用するよりも少し汚いですが、プリプロセッサディレクティブを使用してコードをブロックすると、フラグに基づいてコードをコンパイルする方法を構成できます。
http://www.codeproject.com/Articles/304175/Preprocessor-Directives-in-Csharp
以下の#ifMyFlagのコードは、MyFlagが定義されている場合にのみコンパイルされます
#define MyFlag
public void MyMethod()
{
#if MyFlag
// Flag conditional code
#endif
// method-body
}