C# Roslyn 替换方法
Posted
技术标签:
【中文标题】C# Roslyn 替换方法【英文标题】:C# Roslyn replace methods 【发布时间】:2021-11-08 19:44:00 【问题描述】:我想重构(添加前缀)本地声明的方法及其在.cs
文件中的用法
实现这一目标的最佳做法是什么?
我当前的代码只处理声明
using System;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace CodeScanner
internal sealed class Fixer : CSharpSyntaxRewriter
public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
base.VisitInvocationExpression(node);
// replace usages
return node;
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
base.VisitMethodDeclaration(node);
return node.ReplaceNode(node, SyntaxFactory.MethodDeclaration(
node.AttributeLists,
node.Modifiers,
node.ReturnType,
node.ExplicitInterfaceSpecifier,
SyntaxFactory.Identifier("prefix_" + node.Identifier.Value),
node.TypeParameterList,
node.ParameterList,
node.ConstraintClauses,
node.Body,
node.ExpressionBody));
class Program
static void Main(string[] args)
var tree = CSharpSyntaxTree.ParseText(File.ReadAllText("./test.cs"));
var rewriter = new Fixer();
var result = rewriter.Visit(tree.GetRoot());
Console.WriteLine(result.ToFullString());
输入文件
using System;
namespace TopLevel
class Bar
public void test1()
public void test2() Console.WriteLine("str");
public void Fizz()
Console.WriteLine(test1());
Console.WriteLine(test1(test2()));
test2();
输出
using System;
namespace TopLevel
class Bar
public void prefix_test1()
public void prefix_test2() Console.WriteLine("str");
public void prefix_Fizz()
Console.WriteLine(test1());
Console.WriteLine(test1(test2()));
test2();
所需的输出(更改@ Fizz):
using System;
namespace TopLevel
class Bar
public void prefix_test1()
public void prefix_test2() Console.WriteLine("str");
public void prefix_Fizz()
Console.WriteLine(prefix_test1());
Console.WriteLine(prefix_test1(prefix_test2()));
prefix_test2();
【问题讨论】:
你试过什么?确切的问题是什么? @KrisVandermotten:我看到他的问题是方法定义已重命名,但对它的引用却没有。我认为应该改变Console.WriteLine(test1());
-> Console.WriteLine(prefix_test1());
@LeVu 我明白了,只是我不确定编写代码的问题是什么。这个问题不够准确。
我要重命名所有声明的方法,不清楚吗?
@whoopdedoo 您的要求很明确。我不清楚是什么具体问题阻止您编写代码。
【参考方案1】:
我写了一些符合你设定要求的代码。
见.NET Fiddle
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using static Globals;
tree = CSharpSyntaxTree.ParseText(File.ReadAllText("Test.cs"));
compilation = CSharpCompilation.Create("HelloWorld").AddSyntaxTrees(tree);
model = compilation.GetSemanticModel(tree);
new Finder().Visit(tree.GetRoot());
Console.WriteLine(new Rewriter().Visit(tree.GetRoot()).NormalizeWhitespace().ToFullString());
public static class Globals
public static SyntaxTree tree;
public static CompilationUnitSyntax root;
public static CSharpCompilation compilation;
public static SemanticModel model;
public static Dictionary<IMethodSymbol, string> renames = new();
public sealed class Finder : CSharpSyntaxWalker
public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
base.VisitMethodDeclaration(node);
renames.Add(model.GetDeclaredSymbol(node), "prefix_" + node.Identifier.Value);
public sealed class Rewriter : CSharpSyntaxRewriter
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax mds)
IMethodSymbol symbol = model.GetDeclaredSymbol(mds);
mds = (MethodDeclarationSyntax)base.VisitMethodDeclaration(mds);
if (renames.TryGetValue(symbol, out string newName))
mds = mds.ReplaceToken(mds.Identifier, SyntaxFactory.Identifier(newName));
return mds;
[return: NotNullIfNotNull("node")]
public override SyntaxNode Visit(SyntaxNode node)
node = base.Visit(node);
if (node is SimpleNameSyntax sns &&
model.GetSymbolInfo(sns) is Symbol: IMethodSymbol ms && renames.TryGetValue(ms, out string newName)
)
node = sns.ReplaceToken(sns.Identifier, SyntaxFactory.Identifier(newName));
return node;
【讨论】:
以上是关于C# Roslyn 替换方法的主要内容,如果未能解决你的问题,请参考以下文章
Roslyn - OutOfMemoryException 由于内存中加载的程序集