47 votes

Comment modifier le code avant la compilation?

En utilisant Roslyn, je voudrais modifier mon code C # avant la compilation proprement dite. Pour le moment, il me faut juste quelque chose comme:

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

Et sur la base de l'annotation, je voudrais injecter du code au début de la méthode et à la fin de la méthode.

Je suis au courant de PostSharp, mais ce n'est pas ce que j'aimerais.

Est-ce possible de faire avec Roslyn? Et si oui, pourriez-vous me donner un exemple?

20voto

Voici une façon rapide et sale de faire ce que vous voulez. Il est basé sur l'un des commentaires ci-dessus, les points de SebbyLive. C'est juste une preuve de concept, je ne voudrais pas essayer de l'utiliser en production.

L'idée de base est que vous modifiez le compilateur du projet que vous souhaitez modifier. Et cela a changé le compilateur va faire de l'injection de code. Donc, vous auriez besoin d'écrire un nouveau compilateur (AopCompiler.exe) et la définir comme outil de construction de votre projet.

Réglage de la AopCompiler.exe comme l'outil est facile, en vous fichier de projet, vous devez ajouter les deux lignes suivantes:

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

Le AopCompiler qui devait être une simple application console. Cela fait de la modification de code et la compilation de trop. Si vous ne voulez pas modifier le code source, juste le construire, alors le plus simple est d'appeler le csc.exe vous-même:

static void Main(string[] args)
{
  var p = Process.Start(@"C:\Program Files (x86)\MSBuild\14.0\Bin\csc.exe", 
            string.Join(" ", args));
  p.WaitForExit();
}

Donc, si vous définissez ce jusqu'à présent, vous auriez un processus normal de compilation, sans l'aspect de tissage.

À ce stade, si vous découvrez ce qui est dans l' args, vous verrez qu'il existe un chemin de fichier à un .RSP fichier, qui contient tous les paramètres de ligne de commande pour l'csc.exe. Naturellement, ces paramètres contiennent toutes les de la .CS des noms de fichiers trop. Donc vous pu analyser cette .RSP fichier et de trouver toutes les .CS des fichiers, qui font partie de la compilation.

Avec le C# les fichiers à la main, la réécriture peut être fait avec Roslyn. Il existe de nombreux tutoriels sur CSharpSyntaxRewriter, par exemple iciet ici. Vous devez écrire votre propre CSharpSyntaxRewriter, qui vérifie l'attribut donné, puis ajouter la journalisation pour le début de la trouvé des méthodes. L'ajout de la journalisation à la fin de chaque méthode est un peu plus compliqué, car il peut y avoir plusieurs points de sortie. Pour les trouver, vous pouvez utiliser le contrôle de flux de l'analyse. Le haut-Roslyn de flux de contrôle, d'analyse peut vous donner exactement ce que vous êtes après, l' ExitPoints des biens détient l'ensemble des états à l'intérieur d'une région que de sauter à l'extérieur de la région.

Pour obtenir le modèle sémantique (et alors la CFG de l'analyse), vous pouvez faire quelque chose comme ceci:

public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
{
    var semanticModel = _compilation.GetSemanticModel(node.SyntaxTree);
    // semanticModel.AnalyzeControlFlow(node.Block)
    return node;
}

Enfin, pour traiter chacun des fichiers d'entrée, votre AopCompiler, il vous suffit d'appeler votre graveur de l' Visit méthode sur la racine de l'arbre. Que va produire l'arbre modifié, que vous pouvez écrire dans un fichier. (Vous pouvez modifier le fichier d'origine, ou écrire le résultat dans un nouveau, et changer la .RPR le fichier en conséquence.)

Désolé de ne pas fournir un travail complet de la solution, mais j'espère, c'est assez pour vous obtenir a commencé.

8voto

Jeremy Thompson Points 14428

Comme je l'ai souligné dans mon commentaire, il n'est pas disponible actuellement. Bien que vous pourriez mettre quelque chose ensemble à l'aide de l'AOP techniques montré ici avec le Roslyn API de Script pour fournir une solution très flexible.

La réponse correcte à ce point dans le temps est que la Roslyn équipe ont ouvert la proposition/l'enjeu pour la soutenir. Grâce à l' .Net Foundation et Microsoft participant à l'Open Source que vous pouvez lire à ce sujet le développement de fonctionnalités ici:

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

3voto

user942620 Points 51

C'est un peu plus sale que d'utiliser une annotation, mais le blocage du code à l'aide de directives de préprocesseur vous permettra de configurer la manière dont votre code est compilé en fonction des indicateurs.

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

Le code dans le #ifMyFlag ci-dessous ne sera compilé que si MyFlag est défini

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

    #endif

    // method-body 
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X