2017-09-16 54 views
3

我试图用常规C#SyntaxFactory从零开始构造nameof表达式。不幸的是,出于某种原因,Roslyn未能将我的InvocationExpressionSyntax识别为上下文nameof关键字,并在Emit命令后引发错误诊断。通过SyntaxFactory(Roslyn)构造NameOf表达式

在找出错误的过程中,我试着给Roslyn一些有效的代码进行解析,希望能够找到我的语法构造和“正确解析的”之间的一些区别。我在实验上能够很快地追踪到“nameof”标识符标记的差异,但那是我卡住的地方。我找不到在我的nameof令牌和解析的令牌之间有什么不同,但它们仍然有些不同。

当我使用“解析的人”时,一切正常,Emit按预期工作,没有错误。另一方面,当我使用我自己的nameof令牌时,它编译失败,并且Emit抛出错误诊断。

这里是我的代码,我与测试它:

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()); 

如果有人能指出任何区别解析令牌和我的令牌这是造成罗斯林到(正确地)不能绑定nameof表达式到任何“in-code”符号,但不会将其视为上下文关键字,这真的会帮助我。

编译错误:(1,30):错误CS0103:名称 'nameof' 不在当前情况下存在

编译#LanguageVersion: CSharp7

罗斯林版本: (Nuget最新)Microsoft.CodeAnalysis.CSharp v2.3.2

回答

3

如果你看看Identifier的非私人成员,你会看到有财产RawContextualKind 。当你正在分析从码nameof,你会得到这样的上下文类型: enter image description here

但是如果你SyntaxFactory.IdentifierName("nameof")创建标识符你得到这样的: enter image description here

在第二种情况下,nameof被视为正常的标识和是您收到错误的原因。你应该使用SyntaxFactory.Identifier()过载,它允许你指定一个上下文种类:

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

哦,非常感谢你。这使得伎俩。 我一直在'RawKind'周围嗅探,期待一些背景差异,但没有运气。由于它不是公有财产,我不知道另一个“ContextualKind”的存在。你向我展示了另一个我不知道的罗斯林原则。 还有一件事。我可以以某种方式从标记(非反射方式)读取'ContextualKind',或者是我通过'SyntaxFacts.GetContextualKeywordKind(Token.ValueText)'猜测的唯一机会吗? – WELLCZECH

+0

据我所知,没有办法(没有使用反射)。 'Microsoft.CodeAnalysis.CSharpExtensions'中有一个'ContextualKind'方法,但也是内部的。在我看来,这并没有被曝光。 – nejcs