在VS Code中,如何在设计时根据JSON文件自动生成一个.cs文件,而不需要手动构建?
我在模块根目录有一个permissions.json文件,它是权限常量的唯一权威来源。我想要一个Permissions.g.cs文件在我保存JSON的瞬间自动重新生成,这样IDE的 C# IntelliSense就能即时更新,无需触发构建。
我当前有一个Roslyn增量源生成器 (IIncrementalGenerator),通过 <AdditionalFiles> 连接,在构建时能正确生成该类。问题在于它只在编译时运行,而IntelliSense只有在发生 dotnet build 之后才会反映更改,这打乱了工作流程。
我的JSON结构:
{
"Catalog": {
"Access": "catalog.access",
"Items": {
"View": "catalog.items.view",
"Add": "catalog.items.add"
}
}
}
期望的生成输出:
public static partial class Permissions
{
public static class Catalog
{
public const string Access = "catalog.access";
public static class Items
{
public const string View = "catalog.items.view";
public const string Add = "catalog.items.add";
}
}
}
我想要的效果: 编辑 permissions.json → Permissions.g.cs,磁盘上的更新能即时生效 → IDE的 IntelliSense即时刷新——且没有手动构建,也不需要启动任何外部进程。
是否存在一个官方自带的机制,能够在.NET项目中从JSON文件实现真正的设计时 .cs 生成,而无需安装第三方软件包或扩展,并且在VS Code中也能工作?
解决方案
你增量生成器只在完全构建时更新的原因,是通过 <AdditionalFiles> 包含的文件不会被IDE的后台编译器(Roslyn LSP)视为“实时”或会改变状态的输入。为了在你保存JSON文件的瞬间实现即时的IntelliSense更新,你需要做两件事:
- 使用更新后的
context.AdditionalFilesProvider,并结合AnalyzerAdditionalFileProvider,在源生成器中动态检测文件修改。 - 配置你的
.csproj,让Visual Studio/OmniSharp主动监视这个JSON文件。
下面是修改你的设置以实现保存时实时生成的方法。
1.更新源生成器代码
不要只是以传统方式读取附加文件,而要确保你在使用 AdditionalFilesProvider 流水线并监控 SourceText 的变化。
下面是你应该如何构建你的 Initialize 方法,以确保在保存文件时IDE能更新生成器缓存:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using System.IO;
using System.Linq;
[Generator]
public class PermissionGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. Filter for your permissions.json file
IncrementalValuesProvider<AdditionalText> jsonFiles = context.AdditionalFilesProvider
.Where(file => Path.GetFileName(file.Path).Equals("permissions.json", System.StringComparison.OrdinalIgnoreCase));
// 2. Extract the text content and path as a combined model
IncrementalValuesProvider<(string Path, SourceText Content)> jsonContents = jsonFiles
.Select((file, cancellationToken) =>
{
var text = file.GetText(cancellationToken);
return (Path: file.Path, Content: text);
})
// Crucial: Only proceed if content actually changed
.Where(x => x.Content != null);
// 3. Register the source output
context.RegisterSourceOutput(jsonContents, (spc, source) =>
{
string jsonRawText = source.Content.ToString();
// Your custom JSON parsing logic here
// string generatedCode = ParseAndGenerate(jsonRawText);
// Dummy representation of your expected output
string generatedCode = @"
public static partial class Permissions
{
public static class Catalog
{
public const string Access = ""catalog.access"";
public static class Items
{
public const string View = ""catalog.items.view"";
public const string Add = ""catalog.items.add"";
}
}
}";
spc.AddSource("Permissions.g.cs", SourceText.From(generatedCode, System.Text.Encoding.UTF8));
});
}
}
2.更新你的 .csproj(秘密配方)
为了让IDE在保存非代码文件时即时触发后台生成器,你必须明确声明元数据,强制项目系统对其进行监视。
更新你所消费的项目的 .csproj 文件,加入以下具体属性:
<ItemGroup>
<AdditionalFiles Include="permissions.json" Link="permissions.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</AdditionalFiles>
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="FullPath" />
</ItemGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
3. IDE即时更新清单
如果在这些改动后仍未立即更新,请检查以下环境问题:
- Visual Studio / Rider重启:当你改变一个
IIncrementalGenerator自身的体系结构时,IDE会积极缓存旧的DLL。修改并重新构建Generator项目后,必须重启IDE。 - 属性跟踪:
<CompilerVisibleItemMetadata>标签充当钩子,告诉IDE的实时工作区引擎:如果这个文件被修改并保存,就会使与之相关的生成器缓存节点失效。这正是让IntelliSense在不手动构建的情况下点亮的原因。