有没有办法在C#中实现自定义语言功能?

有没有办法在C#中实现自定义语言功能?,c#,syntactic-sugar,language-construct,C#,Syntactic Sugar,Language Construct,我对此困惑了一段时间,我环顾了一下四周,找不到任何关于这个主题的讨论 假设我想要实现一个简单的示例,比如一个新的循环构造:do..until 写得非常类似于做…而 do { //Things happen here } until (i == 15) 通过这样做,可以将其转换为有效的csharp: do { //Things happen here } while (!(i == 15)) 这显然是一个简单的例子,但有没有办法添加这种性质的内容?理想情况下,作为一个Visua

我对此困惑了一段时间,我环顾了一下四周,找不到任何关于这个主题的讨论

假设我想要实现一个简单的示例,比如一个新的循环构造:do..until

写得非常类似于做…而

do {
    //Things happen here
} until (i == 15)
通过这样做,可以将其转换为有效的csharp:

do {
    //Things happen here
} while (!(i == 15))

这显然是一个简单的例子,但有没有办法添加这种性质的内容?理想情况下,作为一个Visual Studio扩展,可以启用语法突出显示等功能。

不,没有办法实现您所说的内容

因为你要问的是定义新的语言结构,新的词汇分析,语言解析器,语义分析器,编译和优化生成的
IL

在这种情况下,您可以使用一些宏/函数

public bool Until(int val, int check)
{
   return !(val == check);
}
像这样使用它

do {
    //Things happen here
} while (Until(i, 15))

不,没有办法实现你所说的

因为你要问的是定义新的语言结构,新的词汇分析,语言解析器,语义分析器,编译和优化生成的
IL

在这种情况下,您可以使用一些宏/函数

public bool Until(int val, int check)
{
   return !(val == check);
}
像这样使用它

do {
    //Things happen here
} while (Until(i, 15))

你不能在C#中创建你自己的语法抽象,所以你能做的最好的事情就是创建你自己的高阶函数。您可以创建
操作
扩展方法:

public static void DoUntil(this Action act, Func<bool> condition)
{
    do
    {
        act();
    } while (!condition());
}

尽管这是否比直接使用
do..while
更可取值得怀疑。

你不能在C#中创建自己的语法抽象,所以你最好创建自己的高阶函数。您可以创建
操作
扩展方法:

public static void DoUntil(this Action act, Func<bool> condition)
{
    do
    {
        act();
    } while (!condition());
}

尽管这是否比直接使用
do..while
更可取还值得怀疑。

微软提出Rolsyn API作为带有公共API的C#编译器的实现。它包含每个编译器管道阶段的单独API:语法分析、符号创建、绑定、MSIL发射。您可以提供自己的语法分析器实现,也可以扩展现有的语法分析器实现,以获得C#编译器和您想要的任何功能

让我们使用Roslyn来扩展C语言!在我的示例中,我将替换do直到语句w/相应的do,同时:

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));
//                }
//            }
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用Roslyn.Compilers.CSharp;
名称空间罗斯林测试
{
班级计划
{
静态void Main(字符串[]参数)
{
变量代码=@“
使用制度;
班级计划{
公开作废我的(){
var i=5;
做{
Console.WriteLine(“你好世界”);
i++;
}
直到(i>10);
}
}
";
//正在将输入代码解析为SynaxTree对象。
var syntaxTree=syntaxTree.ParseCompilationUnit(代码);
var syntaxRoot=syntaxTree.GetRoot();
//在这里,我们将保留所有要替换的节点
var replaceDictionary=newdictionary();
//在所有子代节点中查找do TILL语句
foreach(类型()的syntaxRoot.DegenantNodes()中的var doStatement)
{
//直到令牌被C#编译器视为标识符,它才知道在我们的例子中它是一个关键字。
var untilNode=doStatement.Condition.ChildNodes().OfType().FirstOrDefault((\u node=>
{
返回_node.Identifier.ValueText==“直到”;
}));
//条件被视为参数列表
var conditionNode=doStatement.Condition.ChildNodes().OfType().FirstOrDefault();
if(untilNode!=null&&conditionNode!=null)
{
//让我们替换标识符w/correct while关键字和条件
var whileNode=Syntax.ParseToken(“while”);
var condition=Syntax.ParseExpression(“(!”+conditionNode.GetFullText()+”);
var newDoStatement=doStatement.WithWhileKeyword(whileNode).WithCondition(condition);
//积累所有替代品
replaceDictionary.Add(doStatement,newDoStatement);
}
}
syntaxRoot=syntaxRoot.ReplaceNodes(replaceDictionary.Keys,(node1,node2)=>replaceDictionary[node1]);
//输出预处理代码
Console.WriteLine(syntaxRoot.GetFullText());
}
}
}
///////////
//输出://
///////////
//使用制度;
//班级计划{
//公开作废我的(){
//var i=5;
//做{
//Console.WriteLine(“你好世界”);
//i++;
//                    }
//而(!(i>10));
//                }
//            }

现在,我们可以使用Roslyn API编译更新后的语法树,或者将syntaxRoot.GetFullText()保存到文本文件中,并将其传递给csc.exe。

微软建议将Rolsyn API作为带有公共API的C#编译器的实现。它包含每个编译器管道阶段的单独API:语法分析、符号创建、绑定、MSIL发射。您可以提供自己的语法分析器实现,也可以扩展现有的语法分析器实现,以获得C#编译器和您想要的任何功能

让我们使用Roslyn来扩展C语言!在我的示例中,我将替换do直到语句w/相应的do,同时:

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));
//                }
//            }
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用Roslyn.Compilers.CSharp;
名称空间罗斯林测试
{
班级计划
{
静态void Main(字符串[]参数)
{
变量代码=@“
使用制度;
班级计划{
公共v