【问题标题】:String escaping issue with Roslyn statement creationRoslyn 语句创建的字符串转义问题
【发布时间】:2012-07-11 05:37:50
【问题描述】:

我有以下代码,它构建了一个调用 Roslyn 代码的 Roslyn 语句,但我遇到了字符串转义的问题。

代码如下:

        var parseStatementArgument = "var statement = Syntax.ParseStatement(\\\"Console.WriteLine (\\\"Hello {0}\\\", parameter1);\\\");";

        var st = Syntax.InvocationExpression(
                                    Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName("Syntax"), Syntax.IdentifierName("ParseStatement")))
                                        .AddArgumentListArguments(
                                            Syntax.Argument(Syntax.LiteralExpression(
                                                SyntaxKind.StringLiteralExpression,
                                                Syntax.Literal(
                                                    text: "\"" + parseStatementArgument + "\"",
                                                    value: parseStatementArgument)
                                    )));

        var variableDeclarator = Syntax.VariableDeclarator(Syntax.Identifier("statement"))
            .WithInitializer(Syntax.EqualsValueClause(st));

        var varStatement = Syntax.VariableDeclaration(Syntax.IdentifierName("var"), Syntax.SeparatedList(variableDeclarator));

        var varStatementText = varStatement.Format().GetFormattedRoot().GetFullText() + ";";

        var scriptEngine = new ScriptEngine(
            new [] {
                MetadataReference.Create("Roslyn.Compilers"),
                MetadataReference.Create("Roslyn.Compilers.CSharp"),
                MetadataReference.Create("Roslyn.Services"),
                MetadataReference.Create("Roslyn.Services.CSharp")
            },
            new [] {
                "System",
                "Roslyn.Compilers.CSharp",
                "Roslyn.Scripting",
                "Roslyn.Scripting.CSharp",
                "Roslyn.Services"
            });

        var session = Session.Create();

        scriptEngine.Execute(varStatementText, session);

        scriptEngine.Execute("Console.WriteLine (statement.Format().GetFormattedRoot().GetFullText());", session);

问题是通过脚本引擎执行打印到控制台窗口的“语句”会错过“Hello {0}”字符串周围的反斜杠。如果我添加双重转义(在参数中添加额外的 \,Roslyn 将引发有关缺少逗号的编译错误。

如何更新此代码以将我想要的内容的语法正确版本放入语句变量中?

【问题讨论】:

    标签: c# roslyn


    【解决方案1】:

    如何切换到使用逐字字符串级别,并在添加节点时添加另一个级别的转义。

    类似:

        var parseStatementArgument = @"var statement = Syntax.ParseStatement(@""Console.WriteLine (""""Hello {0}"""", parameter1);"");";
        var st = Syntax.InvocationExpression(
                                    Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName("Syntax"), Syntax.IdentifierName("ParseStatement")))
                                        .AddArgumentListArguments(
                                            Syntax.Argument(Syntax.LiteralExpression(
                                                SyntaxKind.StringLiteralExpression,
                                                Syntax.Literal(
                                                    text: "@\"" + parseStatementArgument.Replace("\"", "\"\"") + "\"",
                                                    value: parseStatementArgument)
                                    )));
    

    【讨论】:

    • 不,我试图实现的是构造相同的语句,但这只是一个转折,它可以是任何其他 var x = Syntax.ParseStatement ("...");代码。
    • 然后你得到这个错误,我提到过:未处理的异常:Roslyn.Compilers.CompilationErrorException: (1,80): error C S1003: Syntax error, ',' expected.
    • 当我测试您的解决方案时,在复制/粘贴过程中出现了问题,因为现在它运行正确:-( 所以这个逐字语法可以成为一个解决方案。
    【解决方案2】:

    根据 Kevin 关于如何为文字替换字符串的提示,我发现这是一个可行的解决方案,但它引发了另一个问题。

    解决办法:

            var parseStatementArgument = "var statement = Syntax.ParseStatement(\\\"Console.WriteLine (\\\\\\\"Hello {0}\\\\\\\", parameter1);\\\");";
    
            var st = Syntax.InvocationExpression(
                                        Syntax.MemberAccessExpression(SyntaxKind.MemberAccessExpression, Syntax.IdentifierName("Syntax"), Syntax.IdentifierName("ParseStatement")))
                                            .AddArgumentListArguments(
                                                Syntax.Argument(Syntax.LiteralExpression(
                                                    SyntaxKind.StringLiteralExpression,
                                                    Syntax.Literal(
                                                        text: "\"" + parseStatementArgument + "\"",
                                                        value: parseStatementArgument.Replace ("\\\\\\", "\\"))
                                        )));
    

    现在它正确地输出了一个语法正确且编译良好的代码 sn-p。

    它提出的问题是我必须修改源字符串而不是派生字符串才能获得正确的结果。使用 Roslyn 重写代码或生成代码时,不需要双倍或三倍转义字符串文字以使 Roslyn 能够正确处理,这可能是 Roslyn 问题,我希望有人能阐明一个优雅的解决方案适用于所有类型的字符串。

    【讨论】:

    • 嗯,这是一个有点深奥的案例 - 您尝试创建 Parse 语句,然后将其输入执行。为什么不只解析整个原始输入,对其进行转换,将其字符串化,然后执行呢?为什么要添加额外的间接构建语句来进行解析?
    • 执行只是我添加的一个附加步骤,正如我们之前谈到的,需要完整的构建,才能构建构建 Roslyn 代码的代码。因此,我传递给脚本引擎的语句既可以执行,也可以粘贴到方法中。如果您在 DSL 转换期间使用这种东西并在运行时进行转换,我认为您需要执行转换而不关心您在转换期间构建的源代码。
    猜你喜欢
    • 2017-12-29
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-22
    相关资源
    最近更新 更多