我正在尝试使用以下代码片段在内存中运行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
、netstandard
和System.Core
(所需的一切,尽管可能还缺少另一个MetadataReference
?
我确实发现了这个GitHub问题,它似乎描述了一个非常相似的问题,如果不是同一个问题的话。
我很想知道我在这里是否做错了什么,是否还有其他参考资料我遗漏了,或者我是否完全遗漏了其他东西。
通过反编译源代码并逐步了解属性如何成为ExtendedErrorTypeSymbol
,我发现除了resultKind和候选类型之外,还可以找到DiagnosticBag
。在这个袋子里,实际的问题显示出来了:
错误CS0012:类型"Attribute"是在未引用的程序集中定义的。必须添加对程序集"System.Runtime,Version=5.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"的引用。
我的印象是我的代码添加正确,但幸运的是,使用这个错误,我能够进一步搜索,并遇到了这个堆栈溢出问题。这似乎意味着,出于某种原因(我不能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的引用,但现在我知道在哪里可以找到诊断包,其中包含关于实际错误的其他信息,这是一个简单的解决方案。