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

如何使用CSharp.SyntaxFactory为nameof正确指定Roslyn的SyntaxNodes?

解决Roslyn构建nameof(Array.Length)语法节点的问题

你遇到的问题核心是:nameof不是普通的方法调用,Roslyn为它提供了专门的NameOfExpression语法节点类型,而你之前用InvocationExpression来模拟,导致编译器把它当成了一个不存在的方法名,自然会报错。

修正方案

把原来构建InvocationExpression的代码替换成NameOfExpression,具体步骤如下:

  1. 替换InvocationExpression(IdentifierName("nameof"))为NameOfExpression()
  2. 给NameOfExpression传入目标表达式(也就是Array.Length的成员访问表达式)

修正后的字段声明代码

FieldDeclaration(
    VariableDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword)))
    .WithVariables(
        SingletonSeparatedList(
            VariableDeclarator(Identifier("Bar"))
            .WithInitializer(
                EqualsValueClause(
                    NameOfExpression(
                        MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression,
                            IdentifierName("Array"),
                            IdentifierName("Length"))))))))
.WithModifiers(
    TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.ConstKeyword)))

完整修正后的测试代码

替换你的Compile方法中的rootNode部分,完整代码如下:

[Fact]
public void Compile() {
    var rootNode = CompilationUnit()
        .WithUsings(SingletonList(UsingDirective(IdentifierName("System"))))
        .WithMembers(
            SingletonList<MemberDeclarationSyntax>(
                NamespaceDeclaration(IdentifierName("CompilationTests"))
                .WithMembers(
                    SingletonList<MemberDeclarationSyntax>(
                        ClassDeclaration("Foo")
                        .WithMembers(
                            SingletonList<MemberDeclarationSyntax>(
                                // 这里是修正后的字段声明
                                FieldDeclaration(
                                    VariableDeclaration(PredefinedType(Token(SyntaxKind.StringKeyword)))
                                    .WithVariables(
                                        SingletonSeparatedList(
                                            VariableDeclarator(Identifier("Bar"))
                                            .WithInitializer(
                                                EqualsValueClause(
                                                    NameOfExpression(
                                                        MemberAccessExpression(
                                                            SyntaxKind.SimpleMemberAccessExpression,
                                                            IdentifierName("Array"),
                                                            IdentifierName("Length"))))))))
                                .WithModifiers(
                                    TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.ConstKeyword))))))))
        .NormalizeWhitespace();

    var compilation = CSharpCompilation.Create(
        "MyAssembly",
        new[] { CSharpSyntaxTree.Create(rootNode, CSharpParseOptions.Default, isGeneratedCode: true) },
        new[] { MetadataReference.CreateFromFile(typeof(Array).Assembly.Location) },
        new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
    );

    using var memoryStream = new MemoryStream();
    var result = compilation.Emit(memoryStream);

    if (!result.Diagnostics.IsEmpty) {
        foreach (var diagnostic in result.Diagnostics)
            _output.WriteLine(diagnostic.ToString());
        _output.WriteLine(string.Empty);
    }

    _output.WriteLine(rootNode.ToString());
    Assert.True(result.Success);
}

为什么之前的方式不行?

Roslyn的语法模型严格区分语言特性对应的节点类型:

  • 普通方法调用用InvocationExpression
  • nameof运算符作为C#的特殊语法,有自己的NameOfExpression节点

当你用InvocationExpression模拟时,编译器会把nameof解析为一个普通的标识符(方法名),而不是关键字,所以会报"nameof不存在"的错误;同时Array.Length在普通调用参数中会被当成实例成员访问,而nameof内部的表达式是不需要实例的,这也是第二个错误的原因。

修正后,Roslyn会正确识别nameof运算符,编译自然就能通过了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 15:17:44