using System;
using System.Collections;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
namespaceHelloWorld
{
classProgram
{
staticvoidMain(string[] args)
{
Console.WriteLine("Hello World!");
}
staticvoidMain1()
{
Console.WriteLine("HelloMain1!");
}
}
}
这段字符串中包含 5 个 using 引用,一个类型声明,2 个方法(1 个带参数空返回值,1 个不带参数空返回值)。
然后我们使用 VS 打开这个代码,用可视化语法树工具查看,你就能理解为什么叫语法树分析了。左边是源代码,右边就是工具分析出的这个源代码的语法树结构。第一层根节点叫【CompilationUnit】又叫编译单元,相当于一个文件就是一个单独的编译单元,而且呈现树形生长。你把鼠标移到对应的源代码元素上,都会在右侧可视化工具中找到对应的树节点。
再分别看可视化的语法树也正常长出来了,在线的分析工具也能分析出来。但是我们作为开发人员肯定知道,我要 INT 你返回 string,能用才怪呢,逻辑就对不上。在 VS 中飘红是因为他有检测,如果你用记事本写,是不是没啥问题,符合 C# 语法,但它没有足够的信息来标识所引用的内容是什么意思。因为名称可能表示一种类型,方法,局部变量,语义不一样。这个时候就要说另外一个东西了,就是语义分析,就是我解析生成了语法结构,我还得知道每个节点代表什么意思,他的意义是什么。只有知道了语义之后才能真正'活'起来。
publicconststring ProgramText = @"
using System;
using System.Collections;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
static void Main1()
{
var list = new List() { "21" };
list.Add("c");
Console.WriteLine("Hello, Main1!");
}
}
}";
1. 语法分析
直接从语法节点获取返回类型 && 使用语法树分析遍历每个节点。
staticvoidMain(string[] args)
{
SyntaxTree tree = CSharpSyntaxTree.ParseText(ProgramText);
CompilationUnitSyntax root = tree.GetCompilationUnitRoot();
WriteLine($"语法树有 {root.Members.Count} 个元素在里面.");
WriteLine($"这个语法树有 {root.Usings.Count} using 语句,分别是:");
foreach (UsingDirectiveSyntax element in root.Usings)
WriteLine($"\t{element.Name}");
MemberDeclarationSyntax firstMember = root.Members[0];
WriteLine($"第一个成员是:{firstMember.Kind()}.");
var helloWorldDeclaration = (NamespaceDeclarationSyntax)firstMember;
WriteLine($"命名空间{helloWorldDeclaration.Name}下声明了 {helloWorldDeclaration.Members.Count} 个成员.");
WriteLine($"第一个成员的类型是:{helloWorldDeclaration.Members[0].Kind()}.");
var programDeclaration = (ClassDeclarationSyntax)helloWorldDeclaration.Members[0];
WriteLine($"有 {programDeclaration.Members.Count} 个成员定义在 {programDeclaration.Identifier} 类中.");
//直接从语法节点获取返回类型for (int i = 0; i < programDeclaration.Members.Count; i++)
{
WriteLine($"第{i+1}个成员是一个 {programDeclaration.Members[i].Kind()}类型.");
var mainDeclaration = (MethodDeclarationSyntax)programDeclaration.Members[i];
WriteLine($"{mainDeclaration.Identifier}:方法的返回类型是:{mainDeclaration.ReturnType}.");
WriteLine($"方法有:{mainDeclaration.ParameterList.Parameters.Count} 个参数.");
foreach (ParameterSyntax item in mainDeclaration.ParameterList.Parameters)
WriteLine($"{item.Identifier} 参数的类型是:{item.Type}.");
WriteLine($"{mainDeclaration.Identifier} 方法体内容如下:");
WriteLine(mainDeclaration.Body.ToFullString());
}
}