.net Roslyn:SyntaxTree编译失败,而SyntaxTree编译的字符串工作[重复]

dtcbnfnu  于 2023-08-08  发布在  .NET
关注(0)|答案(1)|浏览(107)

此问题在此处已有答案

Constructing NameOf expression via SyntaxFactory (Roslyn)(1个答案)
6天前关门了。

**[编辑]解决方法:**问题通过下面的答案解决。我使用了这部分代码:

SyntaxFactory.IdentifierName(
    SyntaxFactory.Identifier(
        SyntaxFactory.TriviaList(),
        SyntaxKind.NameOfKeyword,
        "nameof",
        "nameof",
        SyntaxFactory.TriviaList()))

字符串
不幸的是,没有像 SyntaxFactory.TypeOfExpression 这样的模式。

**问题:**我正在编写一个代码生成器(使用Roslyn),它使用 nameof。当我尝试用Roslyn编译准备好的 SyntaxTree 时,它失败了,错误是“*error CS 0103:名称'nameof'在当前上下文中不存在 *",而当我解析为 SyntaxTree 时,同一 SyntaxTree 编译的全文没有错误。

这是我在StackOverflow上的第一篇文章,提前感谢您的理解。
我正在写一个代码生成器(使用Roslyn),它使用 nameof。我的编译单元准备如下:

private static CompilationUnitSyntax PrepareCompilationUnit(bool useNameof)
{
    ArrowExpressionClauseSyntax arrowExpression = useNameof
        ? SyntaxFactory.ArrowExpressionClause(
            SyntaxFactory.InvocationExpression(
                SyntaxFactory.IdentifierName(
                        SyntaxFactory.Token(SyntaxKind.NameOfKeyword).ToString()),
                    SyntaxFactory.ArgumentList(
                        SyntaxFactory.SeparatedList(
                            new[] { SyntaxFactory
                                        .Argument(SyntaxFactory
                                            .IdentifierName(PROPERTY_NAME)) }))))
        : SyntaxFactory.ArrowExpressionClause(
                SyntaxFactory.LiteralExpression(
                    SyntaxKind.StringLiteralExpression,
                    SyntaxFactory.Literal(PROPERTY_NAME)));

    PropertyDeclarationSyntax property = SyntaxFactory.PropertyDeclaration(
            SyntaxFactory.ParseTypeName("string"),
            SyntaxFactory.ParseName(PROPERTY_NAME).ToString())
                .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
                .WithExpressionBody(arrowExpression)
                .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));

    ClassDeclarationSyntax classDefinition =
        SyntaxFactory
            .ClassDeclaration(
                SyntaxFactory
                    .Identifier(
                        SyntaxFactory
                            .ParseTypeName(CLASS_NAME).ToString()))
            .AddModifiers(
                SyntaxFactory.Token(SyntaxKind.PublicKeyword))
            .AddMembers(new[] { property });

    NamespaceDeclarationSyntax @namespace = SyntaxFactory
        .NamespaceDeclaration(
            SyntaxFactory
                .ParseName(NAMESPACE_NAME))
                .AddMembers(classDefinition)
        .NormalizeWhitespace();

    return SyntaxFactory
        .CompilationUnit()
        .WithMembers(
            SyntaxFactory
                .SingletonList<MemberDeclarationSyntax>(@namespace));
}


在编译单元准备好之后,我尝试编译这个并使用下面列出的4种方法创建准备好的类的示例:
1.使用 nameof 关键字
1.从编译单元 SyntaxTree 中获取文本,然后基于该文本构建新的 SyntaxTree,并编译新的 SyntaxTree ->工作->我得到了一个正确创建的示例
1.基于编译单元 *SyntaxTree * 构建新的 *SyntaxTree *,编译新的 SyntaxTree ->**不工作->我得到一个“error CS 0103:在编译过程中,当前上下文“”中不存在名称“nameof”
1.使用文字串
1.从编译单元SyntaxTree中获取文本,然后基于该文本构建新的 SyntaxTree,并编译新的 SyntaxTree ->它工作->我得到了一个正确创建的示例
1.基于编译单元 SyntaxTree 构建新的 *SyntaxTree *,并编译新的 SyntaxTree ->工作->我得到了一个正确创建的示例
主要功能如下:

private static void Main(string[] args)
{
    CompilationUnitSyntax compilationUnit = PrepareCompilationUnit(useNameof: true);
    
    SaveToFile(compilationUnit);
    
    object test1 = CreateInstance(
        compilationUnit: compilationUnit,
        compileFromParsedString: true); // return instance
    object test2 = CreateInstance(
        compilationUnit: compilationUnit,
        compileFromParsedString: false); // return null
    
    compilationUnit = PrepareCompilationUnit(useNameof: false);
    
    SaveToFile(compilationUnit);
    
    test1 = CreateInstance(
        compilationUnit: compilationUnit,
        compileFromParsedString: true); // return instance
    test2 = CreateInstance(
        compilationUnit: compilationUnit,
        compileFromParsedString: false); // return instance
}


CreateInstance代码:

private static object CreateInstance(
    CompilationUnitSyntax? compilationUnit,
    bool compileFromParsedString = false)
{
    object result = null;

    var options = new CSharpParseOptions(LanguageVersion.Latest);

    var syntaxTree = compileFromParsedString
        ? SyntaxFactory.ParseSyntaxTree(compilationUnit.ToFullString(), options)
        : SyntaxFactory.SyntaxTree(compilationUnit, options);

    var trustedAssembliesPaths = ((string)AppContext
        .GetData("TRUSTED_PLATFORM_ASSEMBLIES"))
        .Split(Path.PathSeparator);

    var neededAssemblies = new[]
    {
            typeof(object).Assembly.GetName().Name
    };
    List<PortableExecutableReference> references = trustedAssembliesPaths
        .Where(p => neededAssemblies.Contains(Path.GetFileNameWithoutExtension(p)))
        .Select(p => MetadataReference.CreateFromFile(p))
        .ToList();

    var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
        .WithOverflowChecks(true)
        .WithOptimizationLevel(OptimizationLevel.Debug);

    var compilation = CSharpCompilation
        .Create(Guid.NewGuid().ToString("N"), options: compilationOptions)
        .AddReferences(references)
        .AddSyntaxTrees(syntaxTree);

    try
    {
        using MemoryStream dllStream = new MemoryStream();
        Assembly assembly = null;
        EmitResult emitResult = compilation.Emit(dllStream);

        if (emitResult.Success)
        {
            assembly = Assembly.Load(dllStream.ToArray());
            result = assembly.CreateInstance($"{NAMESPACE_NAME}.{CLASS_NAME}");
        }
        else
        {
            foreach (var el in emitResult.Diagnostics)
            {
                Console.WriteLine(el);
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }

    return result;
}


我发现,问题出在 nameof 表达式创建上。当我使用表达式解析器而不是手动创建invocationExpression时,问题也得到了解决(创建有效的示例):

var parsed = SyntaxFactory.ParseExpression($"nameof({PROPERTY_NAME})"))

var created = SyntaxFactory.InvocationExpression(
                SyntaxFactory.IdentifierName(
                        SyntaxFactory.Token(SyntaxKind.NameOfKeyword).ToString()),
                        SyntaxFactory.ArgumentList(
                            SyntaxFactory.SeparatedList(
                                new[] { SyntaxFactory
                                            .Argument(SyntaxFactory
                                                .IdentifierName(PROPERTY_NAME)) }))))


我意识到这个问题是由 IdentifierNameSyntax节点的 RawContextualkind 引起的。 解析表达式是 SyntaxKind.NameOfKeyword,创建表达式是 SyntaxKind.IdentifierToken
谁能告诉我如何在不解析字符串的情况下创建 nameof 表达式(在我看来这太硬编码了)?
生成的代码(使用 nameof 和string literal):

namespace namespaceExample
{
    public class ClsExample
    {
        public string TestName => nameof(TestName);
    }
}
namespace namespaceExample
{
    public class ClsExample
    {
        public string TestName => "TestName";
    }
}

的字符串

aurhwmvo

aurhwmvo1#

我正在写一个代码生成器(使用Roslyn),它使用nameof。当我尝试用Roslyn编译准备好的SyntaxTree时,它失败了,错误是“error CS0103:名称'nameof'不存在于当前上下文”中,而当我将语法树解析为语法树时,相同语法树编译的全文没有错误。
这意味着您正在创建一个编译器无法识别的格式错误的树。可以人为地创建对应于相同文本的不同树,但有一个树可以保证是正确的,这是编译器在解析文本时生成的形式。
要知道如何构造给定的树,最简单的方法是使用Roslyn Quoter
创建nameof调用语法的正确代码如下:

SyntaxFactory.InvocationExpression(
                                        SyntaxFactory.IdentifierName(
                                            SyntaxFactory.Identifier(
                                                SyntaxFactory.TriviaList(),
                                                SyntaxKind.NameOfKeyword,
                                                "nameof",
                                                "nameof",
                                                SyntaxFactory.TriviaList())))
                                    .WithArgumentList(
                                        SyntaxFactory.ArgumentList(
                                            SyntaxFactory.SingletonSeparatedList<ArgumentSyntax>(
                                                SyntaxFactory.Argument(
                                                    SyntaxFactory.IdentifierName(PROPERTY_NAME)))))

字符串

相关问题