1

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はコンマの欠落に関するコンパイルエラーを発生させます。

このコードを更新して、ステートメント変数に必要なものの構文的に正しいバージョンを取得するにはどうすればよいですか?

4

2 に答える 2

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)
                                )));
于 2012-07-11T15:49:32.457 に答える
0

リテラルの文字列を置き換える方法に関するケビンのヒントに基づいて、私は遊んでみましたが、これが機能する解決策であることがわかりましたが、別の問題が発生しました。

ソリューション:

        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 ("\\\\\\", "\\"))
                                    )));

構文的に正しく、適切にコンパイルされるコード スニペットが正しく出力されるようになりました。

発生する問題は、正しい結果を得るために派生文字列ではなくソース文字列を変更する必要があることです。コードを書き直したり、Roslyn でコードを生成したりする場合、Roslyn がそれを正しく処理できるようにするためにエスケープ文字列リテラルを 2 倍または 3 倍にする必要はありません。おそらくそれは Roslyn の問題です。誰かがエレガントなソリューションに光を当ててくれることを願っています。あらゆる種類の文字列で機能します。

于 2012-07-11T17:15:29.147 に答える