使用CSharpSyntaxTree提取C#脚本独立可执行语句遇阻求助
解决提取独立可执行语句的问题
我之前在做类似的C#代码片段分析工具时也踩过这个坑!你当前用root.DescendantNodes().OfType<StatementSyntax>()会拿到所有层级的语句——包括方法体内部、类构造函数里甚至嵌套块里的语句,自然没法精准筛选出那些在using之后、方法/类定义之前的独立可执行代码。
核心思路
我们要找的是不属于任何类、方法、结构体等成员内部的顶级语句(或者命名空间下直接声明的语句)。这些语句要么是C# 9+支持的顶级语句,要么是包裹在命名空间中的直接可执行代码(不过后者在旧版C#里不合法,但你的脚本结构看起来是用了顶级语句特性)。
实现代码
下面是一段可以精准提取目标语句的代码,还能处理嵌套在try-catch、if等块里的子语句:
// 先解析代码并获取语法树根节点 var syntaxTree = CSharpSyntaxTree.ParseText(yourCSharpScriptCode); var root = await syntaxTree.GetRootAsync() as CompilationUnitSyntax; var targetStatements = new List<StatementSyntax>(); // 遍历编译单元的所有顶级成员 foreach (var member in root.Members) { // 处理顶级语句(C# 9+的特性) if (member is StatementSyntax topLevelStmt) { targetStatements.Add(topLevelStmt); // 递归提取块内部的子语句(比如try、catch里的代码) ExtractNestedBlockStatements(topLevelStmt, targetStatements); } // 处理包裹在命名空间里的语句(如果你的脚本有命名空间) else if (member is NamespaceDeclarationSyntax namespaceDecl) { foreach (var nsMember in namespaceDecl.Members) { if (nsMember is StatementSyntax nsStmt) { targetStatements.Add(nsStmt); ExtractNestedBlockStatements(nsStmt, targetStatements); } } } } // 辅助方法:递归提取各类块语句内部的子语句 void ExtractNestedBlockStatements(StatementSyntax statement, List<StatementSyntax> statementList) { // 处理普通代码块(比如{ ... }) if (statement is BlockSyntax block) { foreach (var childStmt in block.Statements) { statementList.Add(childStmt); ExtractNestedBlockStatements(childStmt, statementList); } } // 处理try-catch-finally语句 else if (statement is TryStatementSyntax tryStmt) { ExtractNestedBlockStatements(tryStmt.Block, statementList); foreach (var catchClause in tryStmt.Catches) { ExtractNestedBlockStatements(catchClause.Block, statementList); } if (tryStmt.Finally != null) { ExtractNestedBlockStatements(tryStmt.Finally.Block, statementList); } } // 按需扩展其他块类型,比如if-else、while、for等 else if (statement is IfStatementSyntax ifStmt) { ExtractNestedBlockStatements(ifStmt.Statement, statementList); if (ifStmt.Else != null) { ExtractNestedBlockStatements(ifStmt.Else.Statement, statementList); } } }
代码说明
- 精准筛选层级:我们只遍历
CompilationUnitSyntax(语法树根节点)的直接成员,或者命名空间的直接成员,跳过了类、方法等内部的节点,这样就不会混入方法体里的语句。 - 处理嵌套块:通过辅助方法递归提取
try-catch、if等块内部的子语句,确保不会漏掉嵌套在这些结构里的可执行代码。 - 兼容命名空间:如果你的脚本包裹在命名空间中,代码也能正确提取其中的顶级可执行语句。
用这段代码替代你原来的语句筛选逻辑,就能拿到你想要的那些独立可执行语句了!
内容的提问来源于stack exchange,提问作者Yusuff Sodiq
相关产品推荐
相关产品推荐

