内存中 CSharpCompilation 无法解析属性

Tom*_*Tom 12 c# csharp-source-generator

我尝试使用以下代码片段在内存中运行 C# 源生成器:

var syntaxTree = await SyntaxTreeFromRelativeFile("testdata/IMyInterface.cs");
var compilation = CSharpCompilation.Create("compilation", ImmutableArray.Create(syntaxTree), References);
var generator = new ProxyGenerator();

GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

driver = driver.RunGenerators(compilation);
Run Code Online (Sandbox Code Playgroud)

References设置为编译代码所需的源:

public static readonly ImmutableArray<MetadataReference> References = ImmutableArray.Create<MetadataReference>(
  // System
  MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
  MetadataReference.CreateFromFile(typeof(GCSettings).Assembly.Location),
  MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location),
  MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),

  // JetBrains
  MetadataReference.CreateFromFile(typeof(UsedImplicitlyAttribute).Assembly.Location),

  // some custom ones
);
Run Code Online (Sandbox Code Playgroud)

虽然生成器以这种方式运行得很好,但遗憾的是它没有达到预期的效果,因为源生成器依赖于一个属性来知道是否为指定类型生成源。确切的来源如下:

[MyAttribute]
public interface IMyInterface { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

源生成器正确拾取属性,但它被解析为ExtendedErrorTypeSymbol结果类型为NotAnAttributeType。但是,扩展错误类型符号还有一个候选符号,这正是我期望它匹配的符号。

这让我感到惊讶,因为显然类型是一个属性,并且作为正常编译的一部分运行源生成器实际上确实生成了所有正确的类型。这似乎意味着由于这次运行的内存性质,发生了一些奇怪的事情。

据我所知,我的列表References涵盖了正确认识到某物是属性(mscorlibSystem.RuntimenetstandardSystem.Core)所需的所有内容,尽管也许还MetadataReference缺少另一个?

我确实发现了这个 GitHub 问题,它似乎描述了一个非常相似的问题,即使不是相同的问题。

我很想知道我在这里是否做错了什么,是否缺少其他参考资料,或者我是否完全遗漏了其他东西。

Tom*_*Tom 8

通过反编译源代码并逐步了解属性如何成为ExtendedErrorTypeSymbol,我发现除了 resultKind 和候选类型之外,您还可以找到DiagnosticBag. 在这个包中,显示了实际的问题:

错误 CS0012:类型“属性”是在未引用的程序集中定义的。您必须添加对程序集“System.Runtime,Version=5.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a”的引用。

我的印象是我的代码添加了正确的内容,但是使用这个错误我幸运地能够进一步我的搜索,并遇到了这个 Stackoverflow 问题。这似乎意味着由于某种原因(我不是 100% 确定为什么),以下代码实际上不会添加对 System.Runtime 的正确引用:

MetadataReference.CreateFromFile(typeof(GCSettings).Assembly.Location)
Run Code Online (Sandbox Code Playgroud)

相反,我按照上面链接的答案的示例,并将代码更改为:

private static readonly string dotNetAssemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);

public static readonly ImmutableArray<MetadataReference> References = ImmutableArray.Create<MetadataReference>(
  // .NET assemblies are finicky and need to be loaded in a special way.
  MetadataReference.CreateFromFile(Path.Combine(dotNetAssemblyPath, "mscorlib.dll")),
  MetadataReference.CreateFromFile(Path.Combine(dotNetAssemblyPath, "System.dll")),
  MetadataReference.CreateFromFile(Path.Combine(dotNetAssemblyPath, "System.Core.dll")),
  MetadataReference.CreateFromFile(Path.Combine(dotNetAssemblyPath, "System.Private.CoreLib.dll")),
  MetadataReference.CreateFromFile(Path.Combine(dotNetAssemblyPath, "System.Runtime.dll")),

  // more references, loaded as before
);
Run Code Online (Sandbox Code Playgroud)

出于某种原因,这一切都变得不同了。我还必须添加对 System.Private.CoreLib.dll 的引用,但现在我知道在哪里可以找到诊断包以及有关实际错误的其他信息,这是一个简单的修复。