此问题在此处已有答案:
Constructing NameOf expression via SyntaxFactory (Roslyn)(1个答案)
6天前关门了。
**[编辑]解决方法:**问题通过下面的答案解决。我使用了这部分代码:
SyntaxFactory.IdentifierName(
SyntaxFactory.Identifier(
SyntaxFactory.TriviaList(),
SyntaxKind.NameOfKeyword,
"nameof",
"nameof",
SyntaxFactory.TriviaList()))
字符串
不幸的是,没有像 SyntaxFactory.TypeOfExpression 这样的模式。
**问题:**我正在编写一个代码生成器(使用Roslyn),它使用 nameof。当我尝试用Roslyn编译准备好的 SyntaxTree 时,它失败了,错误是“*error CS 0103:名称'nameof'在当前上下文中不存在 *",而当我解析为 SyntaxTree 时,同一 SyntaxTree 编译的全文没有错误。
这是我在StackOverflow上的第一篇文章,提前感谢您的理解。
我正在写一个代码生成器(使用Roslyn),它使用 nameof。我的编译单元准备如下:
private static CompilationUnitSyntax PrepareCompilationUnit(bool useNameof)
{
ArrowExpressionClauseSyntax arrowExpression = useNameof
? SyntaxFactory.ArrowExpressionClause(
SyntaxFactory.InvocationExpression(
SyntaxFactory.IdentifierName(
SyntaxFactory.Token(SyntaxKind.NameOfKeyword).ToString()),
SyntaxFactory.ArgumentList(
SyntaxFactory.SeparatedList(
new[] { SyntaxFactory
.Argument(SyntaxFactory
.IdentifierName(PROPERTY_NAME)) }))))
: SyntaxFactory.ArrowExpressionClause(
SyntaxFactory.LiteralExpression(
SyntaxKind.StringLiteralExpression,
SyntaxFactory.Literal(PROPERTY_NAME)));
PropertyDeclarationSyntax property = SyntaxFactory.PropertyDeclaration(
SyntaxFactory.ParseTypeName("string"),
SyntaxFactory.ParseName(PROPERTY_NAME).ToString())
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
.WithExpressionBody(arrowExpression)
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
ClassDeclarationSyntax classDefinition =
SyntaxFactory
.ClassDeclaration(
SyntaxFactory
.Identifier(
SyntaxFactory
.ParseTypeName(CLASS_NAME).ToString()))
.AddModifiers(
SyntaxFactory.Token(SyntaxKind.PublicKeyword))
.AddMembers(new[] { property });
NamespaceDeclarationSyntax @namespace = SyntaxFactory
.NamespaceDeclaration(
SyntaxFactory
.ParseName(NAMESPACE_NAME))
.AddMembers(classDefinition)
.NormalizeWhitespace();
return SyntaxFactory
.CompilationUnit()
.WithMembers(
SyntaxFactory
.SingletonList<MemberDeclarationSyntax>(@namespace));
}
型
在编译单元准备好之后,我尝试编译这个并使用下面列出的4种方法创建准备好的类的示例:
1.使用 nameof 关键字
1.从编译单元 SyntaxTree 中获取文本,然后基于该文本构建新的 SyntaxTree,并编译新的 SyntaxTree ->工作->我得到了一个正确创建的示例
1.基于编译单元 *SyntaxTree * 构建新的 *SyntaxTree *,编译新的 SyntaxTree ->**不工作->我得到一个“error CS 0103:在编译过程中,当前上下文“”中不存在名称“nameof”
1.使用文字串
1.从编译单元SyntaxTree中获取文本,然后基于该文本构建新的 SyntaxTree,并编译新的 SyntaxTree ->它工作->我得到了一个正确创建的示例
1.基于编译单元 SyntaxTree 构建新的 *SyntaxTree *,并编译新的 SyntaxTree ->工作->我得到了一个正确创建的示例
主要功能如下:
private static void Main(string[] args)
{
CompilationUnitSyntax compilationUnit = PrepareCompilationUnit(useNameof: true);
SaveToFile(compilationUnit);
object test1 = CreateInstance(
compilationUnit: compilationUnit,
compileFromParsedString: true); // return instance
object test2 = CreateInstance(
compilationUnit: compilationUnit,
compileFromParsedString: false); // return null
compilationUnit = PrepareCompilationUnit(useNameof: false);
SaveToFile(compilationUnit);
test1 = CreateInstance(
compilationUnit: compilationUnit,
compileFromParsedString: true); // return instance
test2 = CreateInstance(
compilationUnit: compilationUnit,
compileFromParsedString: false); // return instance
}
型
CreateInstance代码:
private static object CreateInstance(
CompilationUnitSyntax? compilationUnit,
bool compileFromParsedString = false)
{
object result = null;
var options = new CSharpParseOptions(LanguageVersion.Latest);
var syntaxTree = compileFromParsedString
? SyntaxFactory.ParseSyntaxTree(compilationUnit.ToFullString(), options)
: SyntaxFactory.SyntaxTree(compilationUnit, options);
var trustedAssembliesPaths = ((string)AppContext
.GetData("TRUSTED_PLATFORM_ASSEMBLIES"))
.Split(Path.PathSeparator);
var neededAssemblies = new[]
{
typeof(object).Assembly.GetName().Name
};
List<PortableExecutableReference> references = trustedAssembliesPaths
.Where(p => neededAssemblies.Contains(Path.GetFileNameWithoutExtension(p)))
.Select(p => MetadataReference.CreateFromFile(p))
.ToList();
var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
.WithOverflowChecks(true)
.WithOptimizationLevel(OptimizationLevel.Debug);
var compilation = CSharpCompilation
.Create(Guid.NewGuid().ToString("N"), options: compilationOptions)
.AddReferences(references)
.AddSyntaxTrees(syntaxTree);
try
{
using MemoryStream dllStream = new MemoryStream();
Assembly assembly = null;
EmitResult emitResult = compilation.Emit(dllStream);
if (emitResult.Success)
{
assembly = Assembly.Load(dllStream.ToArray());
result = assembly.CreateInstance($"{NAMESPACE_NAME}.{CLASS_NAME}");
}
else
{
foreach (var el in emitResult.Diagnostics)
{
Console.WriteLine(el);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return result;
}
型
我发现,问题出在 nameof 表达式创建上。当我使用表达式解析器而不是手动创建invocationExpression时,问题也得到了解决(创建有效的示例):
var parsed = SyntaxFactory.ParseExpression($"nameof({PROPERTY_NAME})"))
var created = SyntaxFactory.InvocationExpression(
SyntaxFactory.IdentifierName(
SyntaxFactory.Token(SyntaxKind.NameOfKeyword).ToString()),
SyntaxFactory.ArgumentList(
SyntaxFactory.SeparatedList(
new[] { SyntaxFactory
.Argument(SyntaxFactory
.IdentifierName(PROPERTY_NAME)) }))))
型
我意识到这个问题是由 IdentifierNameSyntax节点的 RawContextualkind 引起的。 解析表达式是 SyntaxKind.NameOfKeyword,创建表达式是 SyntaxKind.IdentifierToken。
谁能告诉我如何在不解析字符串的情况下创建 nameof 表达式(在我看来这太硬编码了)?
生成的代码(使用 nameof 和string literal):
namespace namespaceExample
{
public class ClsExample
{
public string TestName => nameof(TestName);
}
}
namespace namespaceExample
{
public class ClsExample
{
public string TestName => "TestName";
}
}
的字符串
1条答案
按热度按时间aurhwmvo1#
我正在写一个代码生成器(使用Roslyn),它使用nameof。当我尝试用Roslyn编译准备好的SyntaxTree时,它失败了,错误是“error CS0103:名称'nameof'不存在于当前上下文”中,而当我将语法树解析为语法树时,相同语法树编译的全文没有错误。
这意味着您正在创建一个编译器无法识别的格式错误的树。可以人为地创建对应于相同文本的不同树,但有一个树可以保证是正确的,这是编译器在解析文本时生成的形式。
要知道如何构造给定的树,最简单的方法是使用Roslyn Quoter。
创建nameof调用语法的正确代码如下:
字符串