4

我正在尝试使用以下代码片段在内存中运行 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);

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

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

[MyAttribute]
public interface IMyInterface { /* ... */ }

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

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

据我所知,我的清单References涵盖了正确认识到某物是属性(、、、和)所需mscorlib的所有内容System.Runtime,尽管可能还缺少另一个?netstandardSystem.CoreMetadataReference

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

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

4

1 回答 1

1

通过反编译源代码并逐步了解属性如何变为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)

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

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

出于某种原因,这一切都不同了。我还必须添加对 System.Private.CoreLib.dll 的引用,但现在我知道在哪里可以找到包含有关实际错误的附加信息的诊断包,这很容易解决。

于 2021-07-03T16:05:41.007 回答