Trying to construct nameof
expression from scratch using C# SyntaxFactory
. Roslyn fails to recognize my InvocationExpressionSyntax
as a contextual nameof
keyword and throws error diagnostics upon Emit
command.
Tried to give Roslyn valid code to parse in hope that I'll find differences between my syntax construct and the "correctly parsed one". I was able to track the difference down to "nameof" identifier token, but that's where I got stuck. I can't find any difference between my nameof
token and the parsed one, yet they are still somehow different.
When I use the "parsed one" everything works and Emit
works as expected, without errors. On the other hand, when I use my own nameof
token, it fails to compile and Emit
throws error diagnostics.
Code I was testing it on:
var CODE = "class X { void Q() { var q = nameof(Q); } }";
var correctSyntaxTree = CSharpSyntaxTree.ParseText(CODE);
var correctRoot = correctSyntaxTree.GetRoot();
var correctNameOf = correctRoot.DescendantNodes().OfType<InvocationExpressionSyntax>().First();
var correctExpression = (IdentifierNameSyntax)correctNameOf.Expression;
var myNameOf = SyntaxFactory.InvocationExpression (
correctExpression, //Works
//SyntaxFactory.IdentifierName("nameof"), //Doesn't work
//SyntaxFactory.IdentifierName(SyntaxFactory.Token(SyntaxKind.NameOfKeyword)), //System.ArgumentException: 'identifier'
//SyntaxFactory.IdentifierName(correctExpression.Identifier), //Works
//SyntaxFactory.IdentifierName(correctExpression.Identifier.ValueText), //Doesn't work
//correctExpression.WithIdentifier(SyntaxFactory.Identifier("nameof")), //Doesn't work
//correctExpression.WithIdentifier(SyntaxFactory.Identifier(correctExpression.Identifier.ValueText)), //Doesn't work
//SyntaxFactory.IdentifierName("nameof").WithTriviaFrom(correctExpression), //Doesn't work
//correctExpression.CopyAnnotationsTo(SyntaxFactory.IdentifierName("nameof")), //Doesn't work
//SyntaxFactory.IdentifierName(correctExpression.Identifier.WithoutAnnotations().WithoutTrivia()), //Works
SyntaxFactory.ArgumentList (
SyntaxFactory.SingletonSeparatedList (
SyntaxFactory.Argument (
SyntaxFactory.IdentifierName("Q")
)
)
)
);
var newRoot = correctRoot.ReplaceNode(correctNameOf, myNameOf);
var newTree = CSharpSyntaxTree.Create((CSharpSyntaxNode)newRoot);
var compilation = CSharpCompilation.Create (
"Compilation",
new[] { newTree },
references: MsCorLib,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);
var compilationResult = compilation.Emit(new MemoryStream());
Could anyone point out any difference between the parsed token and my token, which is causing the Roslyn to (correctly) not be able to bind the nameof
expression to any "in-code" symbol, yet not treat it as contextual keyword?
Compilation error: (1,30): error CS0103: The name 'nameof' does not exist in the current context
Compilation#LanguageVersion: CSharp7
Roslyn version: (Nuget newest) Microsoft.CodeAnalysis.CSharp v2.3.2
If you look into non-private members of
Identifier
you will see that there is propertyRawContextualKind
. When you are parsingnameof
from code, you will get this contextual kind:But if you create identifier with
SyntaxFactory.IdentifierName("nameof")
you get this:In second case,
nameof
is treated as normal identifier and that is why you receive an error. You should useSyntaxFactory.Identifier()
overload which allows you to specify a contextual kind: