Ali*_*vin 11 c# reflection parsing code-generation codedom
我有一个我正在研究的C#应用程序远程加载它的代码,然后运行它(为了争论,你可以假设应用程序是安全的).
代码是C#,但它作为XML文档发送,解析为字符串,然后编译和执行.
现在,我想要做的事情 - 并且比我预期的要困难得多 - 能够解析整个文档,并且在编译之前,在每行执行之后插入其他命令.
例如,考虑代码:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyCode
{
static class MyProg
{
static void Run()
{
int i = 0;
i++;
Log(i);
}
}
}
Run Code Online (Sandbox Code Playgroud)
解析后我想要的更像是:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyCode
{
static class MyProg
{
static void Run()
{
int i = 0;
MyAdditionalMethod();
i++;
MyAdditionalMethod();
Log(i);
MyAdditionalMethod();
}
}
}
Run Code Online (Sandbox Code Playgroud)
请记住明显的陷阱 - 我不能在每次分号后都有它,因为这在getter/setter中不起作用,即:
转换:
public string MyString { get; set; }
Run Code Online (Sandbox Code Playgroud)
至:
public string MyString { get; MyAdditionalMethod(); set; MyAdditionalMethod(); }
Run Code Online (Sandbox Code Playgroud)
会失败的.和类级声明一样,使用语句等.另外,在一些情况下,我也可以在花括号后添加MyAdditionalMethod() - 比如在委托中,紧跟在if语句之后,或者方法声明等.
所以,我一直在研究CodeDOM,看起来它可能是一个解决方案,但很难弄清楚从哪里开始.我正试图解析整个事情并创建一个我可以解析的树 - 虽然这有点难,考虑到我需要考虑的案例数量.
有没有人知道其他任何解决方案?
Kri*_*is 7
有一些C#解析器,我建议使用Mono或SharpDevelop中的东西,因为它们应该是最新的.我使用SharpDevelop的NRefactory,如果你下载了SharpDevelop的源代码,那么有一个演示和一些UnitTests,它们是一个很好的介绍它的用法.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory;
using System.IO;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.NRefactory.PrettyPrinter;
namespace Parse
{
class Program
{
static void Main(string[] args)
{
string code = @"using System;
using System.Collections.Generic;
using System.Linq;
namespace MyCode
{
static class MyProg
{
static void Run()
{
int i = 0;
i++;
Log(i);
}
}
}
";
IParser p = ParserFactory.CreateParser(SupportedLanguage.CSharp, new StringReader(code));
p.Parse();
//Output Original
CSharpOutputVisitor output = new CSharpOutputVisitor();
output.VisitCompilationUnit(p.CompilationUnit, null);
Console.Write(output.Text);
//Add custom method calls
AddMethodVisitor v = new AddMethodVisitor();
v.VisitCompilationUnit(p.CompilationUnit, null);
v.AddMethodCalls();
output = new CSharpOutputVisitor();
output.VisitCompilationUnit(p.CompilationUnit, null);
//Output result
Console.Write(output.Text);
Console.ReadLine();
}
}
//The vistor adds method calls after visiting by storing the nodes in a dictionary.
public class AddMethodVisitor : ConvertVisitorBase
{
private IdentifierExpression member = new IdentifierExpression("MyAdditionalMethod");
private Dictionary<INode, INode> expressions = new Dictionary<INode, INode>();
private void AddNode(INode original)
{
expressions.Add(original, new ExpressionStatement(new InvocationExpression(member)));
}
public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data)
{
AddNode(expressionStatement);
return base.VisitExpressionStatement(expressionStatement, data);
}
public override object VisitLocalVariableDeclaration(LocalVariableDeclaration localVariableDeclaration, object data)
{
AddNode(localVariableDeclaration);
return base.VisitLocalVariableDeclaration(localVariableDeclaration, data);
}
public void AddMethodCalls()
{
foreach (var e in expressions)
{
InsertAfterSibling(e.Key, e.Value);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
您需要改进访问者以处理更多案例,但这是一个良好的开端.
或者你可以编译原文并使用Cecil进行一些IL操作或尝试一些像PostSharp这样的AOP库.最后,您可以查看.NET Profiling API.