AtomUI Source Generator 源码解析:主题 Token 与控制注册如何自动生成
【免费下载链接】AtomUIAn enhancement and extension library for Avalonia, bringing the Ant Design design language, modern controls, theming, native integrations, and cross-platform UI capabilities to .NET desktop apps.项目地址: https://gitcode.com/gh_mirrors/at/AtomUI
AtomUI 是一款为 .NET 桌面应用带来 Ant Design 设计语言的 Avalonia 增强库,而AtomUI Source Generator(源码生成器)是它的自动化核心:在编译期自动扫描主题 Token 定义与控件包,生成强类型资源键、主题 Schema 与包级注册代码。本文带你用 5 分钟读懂这条"从特性标记到代码落地"的完整流水线。
先搞懂:AtomUI 源码生成器到底是什么?
简单来说,它是一个Roslyn 增量源生成器(IIncrementalGenerator),以 Analyzer 的形式随 NuGet 包分发,编译时由编译器加载,不进入运行时、也不增加应用体积:
- 项目目标框架为
netstandard2.0,标记IsRoslynComponent = true,打包时 DLL 被放入包的analyzers/dotnet/cs目录,见 src/AtomUI.Generator/AtomUI.Generator.csproj。 - 你只需给 Token 类打上特性,编译器就会"变出"一整组强类型代码——无需维护任何手工清单,也没有运行时程序集扫描。
第一步:用特性"标记"主题 Token
生成器的"眼睛"是几个约定好的特性,全部登记在 src/AtomUI.Generator/TargetMarkConstants.cs:
[GlobalDesignToken("MyTheme")] public static class MyThemeTokens { [DesignTokenKind(0)] // 0=Seed, 1=Map, 2=Alias public static Color PrimaryColor { get; set; } }[GlobalDesignToken]:声明一组全局 Token,[DesignTokenKind]标注 Seed/Map/Alias 三阶段,[NotTokenDefinition]可排除个别属性。[ControlDesignToken]:声明某个控件的私有(Own)Token。
生成器通过 Roslyn 的ForAttributeWithMetadataName精准定位这些特性(见 src/AtomUI.Generator/TokenResourceKeyGenerator.cs),再由TokenPropertyWalker这个语法树遍历器逐个属性收集 Token 名称、类型与阶段,见 src/AtomUI.Generator/DesignToken/TokenPropertyWalker.cs。
第二步:Token 资源键如何自动生成
收集完成后,ResourceKeyClassWriter会输出生成文件TokenResourceConst.g.cs(见 src/AtomUI.Generator/DesignToken/ResourceKeyClassWriter.cs),包含三类内容:
| 生成物 | 作用 |
|---|---|
SharedTokenKind枚举 | 所有全局 Token 的强类型清单,取代字符串资源键 |
| 每控件一个 TokenKey 枚举 | 全局 Token 用正整数槽位,控件 Own Token 用负数槽位(-1 - index)编码 |
TokenResourceExtension子类 | 把枚举值映射为真正的ControlTokenResourceKey,越界自动抛异常 |
这意味着你在 XAML 或 C# 中引用 Token 时,拼错名字会在编译期就报错,而不是运行期静默失效。
第三步:控件注册如何自动生成
除了 Token,生成器还会分析构建系统提供的Themes/**/*.axaml主题资产,自动完成三件事:
- 为每个控件生成唯一
ControlTokenIdentity与 descriptor,写入主题 Schema(GeneratedThemeSchemaWriter,见 src/AtomUI.Generator 目录说明); - 生成包级资产清单(
GeneratedControlThemeAssetManifest),记录资产归属与引用关系; - 生成包级注册入口
GeneratedControlPackageRegistration.Register(...),见 src/AtomUI.Generator/Registration/ControlPackageRegistrationWriter.cs。
注册代码会按includeIdentity过滤器挑选控件与资产,并自动处理"资产引用了被排除控件"的联动裁剪。最终你只需要在应用启动时调用一次UseXxxControls()入口——不必逐控件、逐主题手工注册。
生成器全家福:不止 Token 一件事
AtomUI.Generator实际承担了一组编译期职责(完整说明见 docs/modules/generator/overview.md):
| 生成器 | 一句话职责 |
|---|---|
TokenResourceKeyGenerator | 核心:Token 资源键、主题 Schema、资产清单、包级注册 |
LocalizationGenerator | 由[LanguageCatalog]枚举 + XLIFF 2.1 生成强类型本地化扩展 |
LanguageTagsGenerator | 生成常用 BCP 47 语言标签常量 |
DataMemberAccessorGenerator | 为 AOT 生成数据成员访问器注册,避免反射 |
ScopedResourceHostGenerator | 为非 Visual 对象生成资源宿主生命周期样板 |
| Linked-publish 系列 | 仅在 AOT/Trim 发布时生成 Sidecar 与应用级注册计划,普通编译完全排除 |
如何验证生成结果是否完整
在任何一个控件包项目中,构建后查看GeneratedFiles/AtomUI.Generator/目录,应能确认四类输出齐全:exact CLR identity、强类型 Token 键、descriptor/资产清单、包级注册代码。这些生成文件被<Compile Remove>排除、不入库,不要手工修改,把它们当作"编译器打印的收据"来阅读即可。
小结:为什么这套设计值得学习
- 约定优于配置:特性 + 目录约定(
Themes/**/*.axaml)取代手工清单; - 编译期即反馈:Token 拼写错误、粒度配置错误都会以诊断形式直接报在编辑器里;
- AOT 友好:强类型键 + 静态注册计划,让 .NET Native/Trim 场景不再依赖反射扫描。
延伸阅读:docs/modules/generator/linked-registration.md(Linked Registration 深度解析)与 docs/architecture/foundations/aot-linked-registration-pipeline.md(AOT 注册管线架构)。
【免费下载链接】AtomUIAn enhancement and extension library for Avalonia, bringing the Ant Design design language, modern controls, theming, native integrations, and cross-platform UI capabilities to .NET desktop apps.项目地址: https://gitcode.com/gh_mirrors/at/AtomUI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考