如何为IfStatement递归应用WithTriviaFrom并保持代码格式化
问题解决:IfStatement替换后缩进继承与局部格式化
问题原因
你当前的代码仅给最外层IfStatement应用了WithTriviaFrom(exp),内部的Block、ElseClause及子语句不会自动继承原语句的缩进;而直接调用NormalizeWhitespace()会触发全局默认格式化,重置内部块的缩进规则,导致输出格式不符合预期。
解决方案
核心思路是:手动提取原语句的前置缩进,给IfStatement的所有子节点设置匹配的缩进层级,仅对局部节点处理格式,不触动全局文档。
步骤1:提取原语句的前置缩进信息
先从被替换的原表达式exp中提取它的前置空格/制表符,作为基础缩进:
var originalLeadingTrivia = exp.GetLeadingTrivia(); // 把trivia转换成纯缩进字符串(比如原语句的前置空格) var baseIndent = string.Concat(originalLeadingTrivia.Select(t => t.ToString())); // 内部语句的缩进是基础缩进+一级(这里用4空格,可根据代码风格调整) var innerIndent = baseIndent + " ";
步骤2:构建带缩进控制的IfStatement结构
分别处理两个分支的Block,给每个块的左大括号、内部语句设置对应缩进,最后给最外层IfStatement继承原语句的前置trivia:
// 构建32位分支的Block var block32 = SyntaxFactory.Block( SyntaxFactory.ExpressionStatement(GetImportIdentifier32(invocation, name2))) // 给左大括号添加基础缩进,和if语句对齐 .WithLeadingTrivia(SyntaxFactory.Whitespace(baseIndent)) // 给块内的语句添加更深一级的缩进 .WithStatements(block32.Statements.Select(s => s.WithLeadingTrivia(SyntaxFactory.Whitespace(innerIndent)))); // 构建64位分支的Block(逻辑和32位一致) var block64 = SyntaxFactory.Block( SyntaxFactory.ExpressionStatement(GetImportIdentifier64(invocation, name2))) .WithLeadingTrivia(SyntaxFactory.Whitespace(baseIndent)) .WithStatements(block64.Statements.Select(s => s.WithLeadingTrivia(SyntaxFactory.Whitespace(innerIndent)))); // 组装最终的IfStatement,并继承原语句的前置trivia var statement = SyntaxFactory.IfStatement(GetImportCondition(), block32) .WithElse(SyntaxFactory.ElseClause(block64)) .WithLeadingTrivia(originalLeadingTrivia); // 执行节点替换 node = node.ReplaceNode(exp, statement);
关于NormalizeWhitespace的替代用法
如果想局部使用NormalizeWhitespace(),需要给子节点单独调用并指定缩进参数,避免全局格式化:
// 对单个Block局部格式化,指定缩进大小 var block32 = SyntaxFactory.Block(...) .NormalizeWhitespace(indentation: innerIndent.Length) .WithLeadingTrivia(SyntaxFactory.Whitespace(baseIndent));
但这种方式不如手动控制缩进灵活,容易和原上下文格式冲突,优先推荐手动缩进控制方案。
内容的提问来源于stack exchange,提问作者aybe
相关产品推荐
相关产品推荐

