我已经按照documentation创建了一个基本的增量源代码生成器,它输出用属性标记的类的副本:
// Code found in my project
[Copy]
public class MyClass
{
public int Value { get; set; }
}
// Output from the source generator
public class Copy_MyClass
{
public int Value { get; set; }
}
源代码生成本身运行得非常好,但在Visual Studio 2022中使用它时遇到了两个问题:
- 源代码生成器仅在生成期间执行。
- 在重新启动Visual Studio之前,智能感知不会拾取生成的代码。
- 我可以通过将生成的源文件写入项目目录来解决这个问题,但这并不理想,仍然存在上述问题:在我尝试构建之前,更改不会反映出来。
例如,如果我创建一个具有[Copy]属性的新类Foo
,然后尝试在代码中引用Copy_Foo
,Visual Studio将显示Copy_Foo
未定义的错误。
[Copy]
public class Foo { }
public static class TestCopy
{
public static void Test()
{
Copy_Foo foo = new Copy_Foo();
// ^^^^^^^^
// The type or namespace 'Copy_Foo' could not be found
}
}
生成此代码将成功,但Visual Studio将继续认为Copy_Foo
不存在。重新启动后,它将知道Copy_Foo
存在,但在我再次重新启动之前,不会拾取对其所做的任何更改。
我创建了一个小示例,它只输出[Copy]属性。
第一个项目包含源代码生成器:
一个二个一个一个
第二个消耗生成器:
// TestSourceGenerator.Test.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\TestSourceGenerator\TestSourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
// MyClass.cs
namespace TestSourceGenerator.Test
{
[Generated.CopyAttribute]
public class MyClass
{
}
}
如果创建TestSourceGenerator.test项目而不使用ProjectReference
,则在Visual Studio中打开它,然后编辑项目文件以引用分析器,您将看到Visual Studio在[Generated.CopyAttribute]
上显示错误,但项目生成成功。
有没有办法让Visual Studio既在IDE中运行我的源代码生成器,又从生成的代码中拾取符号?根据文档,这似乎应该是一个受支持的用例,甚至是增量源代码生成器存在的主要动机之一。
1条答案
按热度按时间htrmnn0y1#
通常有两个原因让你挣扎,如果不很好地理解,这两个原因都会让你沮丧。
一个问题是Visual Studio不允许分析器程序集在加载后卸载。一旦Visual Studio加载了您的分析器以便在IDE和Intellisense中使用,它将一直使用该版本,直到您关闭Visual Studio,或者至少直到您提高程序集版本。但是,当您点击项目的生成/重新生成时,Visual Studio将生成一个新的msbuild进程,该进程将(通常)加载一个新版本的分析器。因此,您可能最终得到一个构建良好但没有更新IDE和Intellisense的项目。这实际上是一个老问题,并且与生成器没有直接关系,请参见https://github.com/dotnet/roslyn/issues/48083以获取更多信息。(一个建议是,不要通过Visual Studio而是在单元测试的帮助下开发分析器。)
另一个缓存问题是关于
IIncrementalGenerator
的增量构建,但我不确定这是否与您发布的代码相关。无论如何,如果您操作正确,这个新版本的源代码生成器将缓存最后一次执行,并在相关内容未发生更改的情况下为IDE/Intellisense* 重用输出 *。这通常要求您为源语法节点的内容实现自定义等式比较器。但是,如果此比较未能考虑相关内容(即,最后一次按键时实际更改的内容),则不会执行生成器,也不会更新IDE/Intellisense。同样,msbuild可能仍能正常运行,因为每个新生成都会忽略任何以前的输出缓存,并且仅从一开始就为分析器提供每个源节点。