2015-10-24 2 views
43

Roslynを使用して、実際のコンパイルの前にC#コードを修正したいと思います。コンパイルする前にコードを変更するには?

[MyAnotatedMethod] 
public void MyMethod() 
{ 
    // method-body 
} 

そして、アノテーションに基づいて、私はメソッドの開始時にいくつかのコードを挿入したい、と方法の終わりに:今のところ、私はちょうどのようなものが必要になります。

私はPostSharpを認識していますが、それは私が望むものではありません。

これはRoslynで可能ですか?もしそうなら、私に例を挙げてもらえますか?

+2

を定義している場合は、以下にのみコンパイルされます –

+2

でこれはあなたが達成したいものではありません:http://www.sebbylive.com/articles/programming/aspect_oriented_programming_roslyn.aspx?スタンドアローンの実行可能ファイルを使って変更とコンパイルを行い、そのexeをビルドツールとして追加するという基本的な考え方。 – Tamas

+1

私はこれらのような質問が好きです。一方では、[いいえ]と言う伝説があります(https://social.msdn.microsoft.com/forums/vstudio/en-US/3593b4d9-c3f0-4e94-818a-7958930aeb4e/injecting 'Roslynチームはコードインジェクションをサポートすると言っていると言っているが、おそらく最初のものではないかもしれないと言っている[quotes](https://gist.github.com/SimonCropp/8485964) @Bjørn-RogerKringsjåあなたは、Roslynが**これとは違って**実装する方法を通常の実装にどのように期待するのかを教えてください:http://www.codeproject.com/Articles/14334/AOP-using-System-Rlection -Emit-Code-Injection-IL –

答えて

16

ここでは、あなたが望むことを行うためのすばやく汚い方法です。これは上記のコメントの1つで、SebbyLiveを示しています。それは概念の証明に過ぎず、私はそれを本番環境で使用しようとはしません。

基本的な考え方は、変更するプロジェクトのコンパイラを変更することです。そして、この変更されたコンパイラはコードインジェクションを行います。したがって、新しいコンパイラ(AopCompiler.exe)を作成し、それをプロジェクトのビルドツールとして設定する必要があります。

<CscToolPath>$(SolutionDir)AopCompiler\bin\Debug</CscToolPath> 
<CscToolExe>AopCompiler.exe</CscToolExe> 

AopCompilerは、簡単なコンソールアプリケーションでなければなりません:ビルドツールとしてAopCompiler.exeを設定

は、ファイルをプロジェクトに、あなたは次の2行を追加する必要があると思い、簡単です。これは、コードの変更とコンパイルも行っています。 あなたは、最も簡単な方法は、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には多くのチュートリアルがあります。例えば、herehereです。指定された属性をチェックするカスタム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ファイルを変更することができます。)

申し訳ありませんが、完全な実用的なソリューションを提供していないのですが、これで十分です。

+0

-Elementは-Elementが不明です」というメッセージが表示されます。ご覧のとおり、 'project'要素の最後の' .csproj'ファイルに2行を挿入しました。ここで何が間違っていますか? – C4u

7

私のコメントで指摘したように、現在利用できません。あなたは非常に柔軟な解決法を提供するためにhereRoslyn Scripting APIと表示されたAOP技術を使用して何かを一緒に置くことができます。

この時点で正しい答えは、Roslynチームがそれをサポートするための公開提案/問題を持っていることです。あなたはこのことについて読むことができるオープンソースに参加するネット財団とマイクロソフトのおかげで、ここで開発しています:

https://github.com/dotnet/roslyn/issues/5561

3

それは注釈を使用してより少し汚いですが、プリプロセッサディレクティブを使用してコードを遮断することができるようになりますコードに基づいてコードをコンパイルする方法を設定します。

http://www.codeproject.com/Articles/304175/Preprocessor-Directives-in-Csharp

#ifMyFlag内のコードMyFlagは、[Fody](https://github.com/Fody/Fody)もあります

#define MyFlag 
public void MyMethod() 
{ 
    #if MyFlag 
     // Flag conditional code 

    #endif 

    // method-body 
} 
+0

良い答え - これは、何年も前のプロジェクトで、If条件で静的関数呼び出しを使用してこれを思い出します。これは、Attributeよりもはるかに余分な作業ではなく、AOPアプローチよりはるかに実装が簡単です –

関連する問題