Reputation: 212
I've the following code, which builds up a Roslyn statement which calls Roslyn code inside, but I've a problem with string escaping.
Here is the code:
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);
The problem is that the "statement" printed to the console windows via the script engine execution will miss the backslashed around the "Hello {0}" string. If I add double escaping (additional \ into the parameter, Roslyn will raise compile errors about missing commas.
How may I update this code to get a syntactically correct version of what I want into the statement variable?
Upvotes: 1
Views: 1493
Reputation: 212
Based on Kevin's tip on how to replace string for literals I played around and found this as a solution that works, but it raised another problem.
The solution:
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 ("\\\\\\", "\\"))
)));
Now it correctly outputs a code snippet which is syntactically correct and compiles well.
The problem it raises is that I had to modify the source string and not the derived string to get the correct result. When rewriting code or generating code with Roslyn it can not be a requirement to double or triple escape string literals to make Roslyn able to deal with that correctly, maybe its a Roslyn issue, I hope that someone will shed some light on an elegant solution which works for all kind of strings.
Upvotes: 0
Reputation: 11615
How about switching to using verbatim string levels, and just add another level of escaping as you add the node.
Something like:
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)
)));
Upvotes: 1