You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C# Roslyn中实现不同类之间的静态成员迁移?

1 静态成员判断方法

你可以选择两种方式实现判断:

  • 语法层面直接判断修饰符:不需要调用语义模型接口,性能更高,适合快速过滤
    代码示例:
    if (member.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)))
    
  • 语义符号层面判断:判断结果更准确,可覆盖所有特殊场景(比如隐式静态的成员场景)
    代码示例:
    var symbol = semanticModel.GetDeclaredSymbol(member);
    if (symbol != null && symbol.IsStatic)
    

2 静态成员迁移与引用更新方案

实现逻辑分为四步:先预创建目标存储类、迁移成员到目标类、遍历更新所有引用、提交所有变更,完整修改后的代码如下:

// 先定义你的目标静态成员存储类名,可根据需求修改
private const string TargetStaticClassName = "ObfuscationStaticContainer";

public async Task Run(string solutionPath)
{
    m_workspace = MSBuildWorkspace.Create();
    Solution solution = await m_workspace.OpenSolutionAsync(solutionPath);
    var project = solution.Projects.FirstOrDefault();
    if (project == null) return;

    // 第一步:先找到或创建目标存储类
    ClassDeclarationSyntax targetClass = null;
    Document targetClassDocument = null;
    // 这里示例是先找项目里已有的目标类,你也可以直接创建新的文档和类
    foreach (var doc in project.Documents)
    {
        var root = await doc.GetSyntaxRootAsync();
        targetClass = root.DescendantNodes().OfType<ClassDeclarationSyntax>()
            .FirstOrDefault(c => c.Identifier.Text == TargetStaticClassName);
        if (targetClass != null)
        {
            targetClassDocument = doc;
            break;
        }
    }
    // 如果没找到就创建新的目标类,这里简化实现,你可根据需求调整命名空间、访问修饰符
    if (targetClass == null)
    {
        targetClass = SyntaxFactory.ClassDeclaration(TargetStaticClassName)
            .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword));
        var root = SyntaxFactory.CompilationUnit()
            .AddMembers(SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("YourProjectNamespace"))
            .AddMembers(targetClass));
        targetClassDocument = project.AddDocument($"{TargetStaticClassName}.cs", root);
        solution = targetClassDocument.Project.Solution;
        targetClass = (await targetClassDocument.GetSyntaxRootAsync()).DescendantNodes().OfType<ClassDeclarationSyntax>().First();
    }

    // 第二步:遍历所有文档找静态成员
    foreach (var document in project.Documents)
    {
        if (document == targetClassDocument) continue; // 跳过目标类本身
        var syntaxTree = await document.GetSyntaxTreeAsync();
        var semanticModel = await document.GetSemanticModelAsync();
        var root = await syntaxTree.GetRootAsync();
        var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
        
        foreach (var c in classes)
        {
            foreach (var member in c.Members)
            {
                // 用刚才的方法判断静态成员
                if (!member.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword))) continue;
                var memberSymbol = semanticModel.GetDeclaredSymbol(member);
                if (memberSymbol == null) continue;

                // 第三步:迁移成员到目标类
                // 复制成员节点,可根据需求调整修饰符,比如把private改成internal
                var copiedMember = member;
                // 更新目标类的语法树,把成员加进去
                var newTargetClass = targetClass.AddMembers(copiedMember);
                var targetRoot = await targetClassDocument.GetSyntaxRootAsync();
                var newTargetRoot = targetRoot.ReplaceNode(targetClass, newTargetClass);
                solution = targetClassDocument.WithSyntaxRoot(newTargetRoot).Project.Solution;
                // 重新获取更新后的目标类,方便下一次添加
                targetClass = newTargetClass;
                targetClassDocument = solution.GetDocument(targetClassDocument.Id);

                // 第四步:更新所有引用
                var references = await SymbolFinder.FindReferencesAsync(memberSymbol, solution);
                foreach (var reference in references.SelectMany(r => r.Locations))
                {
                    var refDoc = solution.GetDocument(reference.Document.Id);
                    var refRoot = await refDoc.GetSyntaxRootAsync();
                    var refNode = refRoot.FindNode(reference.Location.SourceSpan);
                    // 把引用替换成 目标类名.成员名 的形式
                    var newRefNode = SyntaxFactory.MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        SyntaxFactory.IdentifierName(TargetStaticClassName),
                        SyntaxFactory.IdentifierName(memberSymbol.Name));
                    var newRefRoot = refRoot.ReplaceNode(refNode, newRefNode);
                    solution = refDoc.WithSyntaxRoot(newRefRoot).Solution;
                }

                // 从原类中删除该静态成员
                var newClass = c.RemoveNode(member, SyntaxRemoveOptions.KeepNoTrivia);
                var newRoot = root.ReplaceNode(c, newClass);
                solution = document.WithSyntaxRoot(newRoot).Project.Solution;
                // 更新当前文档的root,避免后续遍历出错
                root = newRoot;
            }
        }
    }

    // 提交所有变更
    m_workspace.TryApplyChanges(solution);
}

注意事项

  • 上述代码为简化实现,实际使用时需要处理泛型成员、重载成员、重名成员、命名空间引用补全等边缘场景
  • 访问修饰符可以根据你的混淆需求调整,比如将原私有静态成员改为内部访问,保证所有引用位置可访问
  • 如果要处理多个项目的情况,需要对所有项目都执行上述遍历逻辑

内容的提问来源于stack exchange,提问作者F Chopin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 22:18:02