我已经对此感到困惑了一段时间,并且四处张望,无法找到有关该主题的任何讨论。
假设我想实现一个简单的示例,例如一个新的循环结构:do..until
写得非常类似。
do { //Things happen here } until (i == 15)
这样做可以将其转换为有效的csharp:
do { //Things happen here } while (!(i == 15))
这显然是一个简单的示例,但是有什么方法可以添加这种性质的东西吗?理想情况是作为Visual Studio扩展来启用语法突出显示等。
Microsoft提出将Rolsyn API作为带有公共API的C#编译器的实现。它为每个编译器管道阶段包含单独的API:语法分析,符号创建,绑定,MSIL发出。您可以提供自己的语法解析器实现或扩展现有的语法解析器实现,以便获得具有所需功能的C#编译器。
罗斯林CTP
让我们使用Roslyn扩展C#语言!在我的示例中,我将替换带有相应的do-while的do-until语句:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Roslyn.Compilers.CSharp; namespace RoslynTest { class Program { static void Main(string[] args) { var code = @" using System; class Program { public void My() { var i = 5; do { Console.WriteLine(""hello world""); i++; } until (i > 10); } } "; //Parsing input code into a SynaxTree object. var syntaxTree = SyntaxTree.ParseCompilationUnit(code); var syntaxRoot = syntaxTree.GetRoot(); //Here we will keep all nodes to replace var replaceDictionary = new Dictionary<DoStatementSyntax, DoStatementSyntax>(); //Looking for do-until statements in all descendant nodes foreach (var doStatement in syntaxRoot.DescendantNodes().OfType<DoStatementSyntax>()) { //Until token is treated as an identifier by C# compiler. It doesn't know that in our case it is a keyword. var untilNode = doStatement.Condition.ChildNodes().OfType<IdentifierNameSyntax>().FirstOrDefault((_node => { return _node.Identifier.ValueText == "until"; })); //Condition is treated as an argument list var conditionNode = doStatement.Condition.ChildNodes().OfType<ArgumentListSyntax>().FirstOrDefault(); if (untilNode != null && conditionNode != null) { //Let's replace identifier w/ correct while keyword and condition var whileNode = Syntax.ParseToken("while"); var condition = Syntax.ParseExpression("(!" + conditionNode.GetFullText() + ")"); var newDoStatement = doStatement.WithWhileKeyword(whileNode).WithCondition(condition); //Accumulating all replacements replaceDictionary.Add(doStatement, newDoStatement); } } syntaxRoot = syntaxRoot.ReplaceNodes(replaceDictionary.Keys, (node1, node2) => replaceDictionary[node1]); //Output preprocessed code Console.WriteLine(syntaxRoot.GetFullText()); } } } /////////// //OUTPUT:// /////////// // using System; // class Program { // public void My() { // var i = 5; // do { // Console.WriteLine("hello world"); // i++; // } //while(!(i > 10)); // } // }
现在,我们可以使用Roslyn API编译更新的语法树,或将语法Root.GetFullText()保存到文本文件并将其传递给csc.exe。