如何使增量源生成器在 Visual Studio 中运行?

Col*_*nee 8 c# visual-studio sourcegenerators .net-6.0

我按照文档创建了一个基本的增量源生成器,它输出用属性标记的类的副本:

// 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; }
}
Run Code Online (Sandbox Code Playgroud)

源代码生成本身工作得很好,但在 Visual Studio 2022 中使用它时我遇到了两个问题:

  • 源生成器仅在构建期间执行。
  • 在我重新启动 Visual Studio 之前,Intellisense 不会获取生成的代码。
    • 我可以通过将生成的源文件写入项目目录来解决这个问题,但这并不理想,并且仍然遇到上述问题:直到我尝试构建时更改才会反映出来。

例如,如果我使用Foo[Copy] 属性创建一个新类,然后尝试在代码中引用,Visual Studio 将显示未定义的Copy_Foo错误。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
    }
}
Run Code Online (Sandbox Code Playgroud)

构建此代码将会成功,但 Visual Studio 将继续认为该代码Copy_Foo不存在。一旦我重新启动,它就会知道它Copy_Foo存在,但在我再次重新启动之前,对其进行的任何更改都不会被拾取。

我创建了一个小示例,它仅输出 [Copy] 属性。

第一个项目包含源生成器:

// TestSourceGenerator.csproj
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
        <IncludeBuildOutput>false</IncludeBuildOutput>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.0.1" />
    </ItemGroup>

    <ItemGroup>
        <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
    </ItemGroup>

</Project>
Run Code Online (Sandbox Code Playgroud)
// TestSourceGenerator.cs
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace TestSourceGenerator
{
    [Generator]
    public class TestSourceGenerator : IIncrementalGenerator
    {
        private const string CopyAttributeSource = @"
namespace Generated
{
    public class CopyAttribute : System.Attribute { }
}";

        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            context.RegisterPostInitializationOutput(ctx => ctx.AddSource("CopyAttribute.g.cs", SourceText.From(CopyAttributeSource, Encoding.UTF8)));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个消耗生成器:

// 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>
Run Code Online (Sandbox Code Playgroud)
// MyClass.cs
namespace TestSourceGenerator.Test
{
    [Generated.CopyAttribute]
    public class MyClass
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

如果创建不带 的 TestSourceGenerator.Test 项目ProjectReference,在 Visual Studio 中打开它,然后编辑项目文件以引用分析器,您将看到 Visual Studio 在 上显示错误[Generated.CopyAttribute],但项目构建成功。

有没有办法让 Visual Studio 在 IDE 中运行我的源代码生成器并从生成的代码中获取符号?根据文档,这似乎应该是一个受支持的用例,甚至是现有增量源生成器的主要动机之一。

Ola*_*son 1

你的挣扎通常有两个原因,如果不能很好地理解,这两个原因都会令人沮丧。

一个问题是 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可能仍然运行良好,因为每个新构建都会忽略任何先前的输出缓存,并且只是从一开始就为分析器提供每个源节点。