[编辑]解决方案:
问题通过以下答案解决了。我使用了这部分代码:
SyntaxFactory.IdentifierName(
SyntaxFactory.Identifier(
SyntaxFactory.TriviaList(),
SyntaxKind.NameOfKeyword,
"nameof",
"nameof",
SyntaxFactory.TriviaList()))
不幸的是,没有作为
SyntaxFactory。表达式类型
。
问题:
我正在编写一个代码生成器(使用Roslyn),它使用
的名称
.当我尝试编译时
SyntaxTree
与Roslyn一起,它因错误而失败”
错误CS0103:名称“nameof”在当前上下文中不存在
”,而当我解析为
SyntaxTree
相同的全文
SyntaxTree
编译完成时没有任何错误。
这是我在StackOverflow上的第一篇帖子,提前感谢您的理解。
我正在编写一个代码生成器(使用Roslyn),它使用
的名称
。我的编制单位编制情况如下:
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种方式创建已准备好的类的实例:
-
使用
的名称
关键字
-
从编译单元获取文本
SyntaxTree
,然后构建新的
SyntaxTree
基于此文本,并编译新的
SyntaxTree
->
它有效->我得到一个正确创建的实例
-
新建
SyntaxTree
基于编译单元
SyntaxTree
,并编译新的
SyntaxTree
->
它不起作用->我得到一个“
错误CS0103:名称“nameof”在当前上下文中不存在
在编译期间
-
使用文字字符串
-
从编译单元SyntaxTree获取文本,然后构建新的
SyntaxTree
基于此文本,并编译新的
SyntaxTree
->
它有效->我得到一个正确创建的实例
-
新建
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;
}
我发现,问题出在
的名称
表达式创建。当我使用表达式解析器而不是手动创建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)) }))))
我意识到问题是由
原始上下文类型
的节点的
标识符名称语法。
是的
SyntaxKind。关键字名称
对于解析的表达式,以及
SyntaxKind。标识符令牌
为创建的一个。
有人能告诉我如何创作吗
的名称
表达式而不解析字符串(在我看来它太硬编码了)?
生成的代码(使用
的名称
和字符串文字):
namespace namespaceExample
{
public class ClsExample
{
public string TestName => nameof(TestName);
}
}
namespace namespaceExample
{
public class ClsExample
{
public string TestName => "TestName";
}
}