我有一个 C# 9.0 源代码生成器,它引用了一个类库,该类库包含一个用于标识要处理的类的属性。我现在正在编写单元测试,如此处所述:
Compilation inputCompilation = CreateCompilation(@"
using Dependncy;
namespace MyCode
{
[Marker]
public partial class SimpleObject
{
[PropertyMarker(0)]
public int Test{get;set;}
}
}
");
var generator = new MyCodeGen();
// Create the driver that will control the generation, passing in our generator
GeneratorDriver driver = CSharpGeneratorDriver.Create(generator);
// Run the generation pass
// (Note: the generator driver itself is immutable, and all calls return an updated version of the driver that you should use for subsequent calls)
driver = driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out var outputCompilation, out var diagnostics);
// We can now assert things about the resulting compilation:
Assert.IsTrue(diagnostics.IsEmpty); // there were no diagnostics created by the generators
Assert.IsTrue(outputCompilation.SyntaxTrees.Count() == 2); // we have two syntax trees, the original 'user' provided one, and the one added by the generator
Assert.IsTrue(outputCompilation.GetDiagnostics().IsEmpty); // verify the compilation with the added source has no diagnostics
// Or we can look at the results directly:
GeneratorDriverRunResult runResult = driver.GetRunResult();
// The runResult contains the combined results of all generators passed to the driver
Assert.IsTrue(runResult.GeneratedTrees.Length == 1);
Assert.IsTrue(runResult.Diagnostics.IsEmpty);
// Or you can access the individual results on a by-generator basis
GeneratorRunResult generatorResult = runResult.Results[0];
Assert.IsTrue(generatorResult.Generator == generator);
Assert.IsTrue(generatorResult.Diagnostics.IsEmpty);
Assert.IsTrue(generatorResult.GeneratedSources.Length == 1);
Assert.IsTrue(generatorResult.Exception is null);
CreateCompilation
看起来像这样
private static Compilation CreateCompilation(string source)
=> CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source) },
new[] { MetadataReference.CreateFromFile(typeof(Binder).GetTypeInfo().Assembly.Location), MetadataReference.CreateFromFile(typeof(MarkerAttribute).GetTypeInfo().Assembly.Location) },
new CSharpCompilationOptions(OutputKind.ConsoleApplication));
但是,生成器将无法识别标记属性(符号不相等)。我想,问题是,在编译中,它们被视为来自另一个程序集:一个来自 UnitTest 中的编译,另一个是源代码生成器中的引用。
源代码生成器获取要与之比较的符号,compilation.GetTypeByMetadataName(typeof(MarkerAttribute).FullName)
但也引用包含程序集本身。我GetDependencyTargetPaths
在官方示例csproj中包含参考。
知道我必须如何创建编译,以便源生成器中的符号相等吗?
编辑 1
我刚刚发现,AttributeClass
似乎与类型匹配(即名称相等),但它的 Kind 属性返回SymbolKind.ErrorType
,而源 gen 获得的属性compilation.GetTypeByMetadataName(typeof(MarkerAttribute).FullName)
返回SymbolKind.NamedType
。所以这可能就是他们不匹配的原因。但是,我仍然不知道为什么符号的解析方式不同。