- 新增 Priority 生成器文档,介绍自动实现 IPrioritized 接口的功能 - 新增 Context Get 注入生成器文档,说明自动注入架构组件的特性 - 更新索引页面,添加新生成器的导航链接和功能描述 - 补充 EnumGenerator 配置选项说明,列出已实现和未实现的选项 - 添加完整的诊断信息说明,涵盖新生成器的所有错误场景
16 KiB
Priority 生成器
自动实现 IPrioritized 接口,为类添加优先级标记
Priority 生成器通过源代码生成器自动实现 IPrioritized 接口,简化优先级标记和排序逻辑的实现。
概述
核心功能
- 自动实现接口:自动实现
IPrioritized接口的Priority属性 - 优先级标记:通过特性参数指定优先级值
- 编译时生成:在编译时生成代码,零运行时开销
- 类型安全:编译时类型检查,避免运行时错误
适用场景
- 系统初始化顺序控制
- 事件处理器优先级排序
- 服务注册顺序管理
- 需要按优先级排序的任何场景
基础使用
标记优先级
使用 [Priority] 特性为类标记优先级:
using GFramework.SourceGenerators.Abstractions.Bases;
[Priority(10)]
public partial class MySystem
{
// 自动生成 IPrioritized 接口实现
}
生成代码
编译器会自动生成如下代码:
// <auto-generated/>
#nullable enable
namespace YourNamespace;
partial class MySystem : global::GFramework.Core.Abstractions.Bases.IPrioritized
{
/// <summary>
/// 获取优先级值: 10
/// </summary>
public int Priority => 10;
}
使用生成的优先级
生成的 Priority 属性可用于排序:
using GFramework.Core.Abstractions.Bases;
// 获取所有实现了 IPrioritized 的系统
var systems = new List<IPrioritized> { system1, system2, system3 };
// 按优先级排序(值越小,优先级越高)
var sorted = systems.OrderBy(s => s.Priority).ToList();
// 依次初始化
foreach (var system in sorted)
{
system.Initialize();
}
优先级值语义
值的含义
| 优先级值范围 | 含义 | 使用场景 |
|---|---|---|
| 负数 | 高优先级 | 核心系统、关键事件处理器 |
| 0 | 默认优先级 | 普通系统、一般事件处理器 |
| 正数 | 低优先级 | 可延迟初始化的系统、非关键处理器 |
PriorityGroup 常量
推荐使用 PriorityGroup 预定义常量来标记优先级:
using GFramework.Core.Abstractions.Bases;
using GFramework.SourceGenerators.Abstractions.Bases;
[Priority(PriorityGroup.Critical)] // -100
public partial class InputSystem : AbstractSystem { }
[Priority(PriorityGroup.High)] // -50
public partial class PhysicsSystem : AbstractSystem { }
[Priority(PriorityGroup.Normal)] // 0
public partial class GameplaySystem : AbstractSystem { }
[Priority(PriorityGroup.Low)] // 50
public partial class AudioSystem : AbstractSystem { }
[Priority(PriorityGroup.Deferred)] // 100
public partial class CleanupSystem : AbstractSystem { }
PriorityGroup 常量定义:
namespace GFramework.Core.Abstractions.Bases;
public static class PriorityGroup
{
public const int Critical = -100; // 关键:输入、网络等
public const int High = -50; // 高:物理、碰撞等
public const int Normal = 0; // 正常:游戏逻辑等
public const int Low = 50; // 低:音频、特效等
public const int Deferred = 100; // 延迟:清理、统计等
}
使用场景
系统初始化顺序
控制系统初始化的顺序,确保依赖关系正确:
using GFramework.Core.Abstractions.Systems;
using GFramework.SourceGenerators.Abstractions.Bases;
using GFramework.Core.Abstractions.Bases;
// 输入系统最先初始化
[Priority(PriorityGroup.Critical)]
public partial class InputSystem : AbstractSystem
{
protected override void OnInit()
{
// 初始化输入处理
}
}
// 物理系统次之
[Priority(PriorityGroup.High)]
public partial class PhysicsSystem : AbstractSystem
{
protected override void OnInit()
{
// 初始化物理引擎
}
}
// 游戏逻辑系统在中间
[Priority(PriorityGroup.Normal)]
public partial class GameplaySystem : AbstractSystem
{
protected override void OnInit()
{
// 初始化游戏逻辑
}
}
// 音频系统可以稍后
[Priority(PriorityGroup.Low)]
public partial class AudioSystem : AbstractSystem
{
protected override void OnInit()
{
// 初始化音频引擎
}
}
在架构中按优先级初始化:
public class GameArchitecture : Architecture
{
protected override void InitSystems()
{
// 获取所有系统并按优先级排序
var systems = this.GetAllByPriority<ISystem>();
foreach (var system in systems)
{
system.Init();
}
}
}
事件处理器优先级
控制事件处理器的执行顺序:
using GFramework.Core.Abstractions.Events;
// 关键事件处理器最先执行
[Priority(PriorityGroup.Critical)]
public partial class CriticalEventHandler : IEventHandler<CriticalEvent>
{
public void Handle(CriticalEvent e)
{
// 处理关键事件
}
}
// 普通处理器在中间执行
[Priority(PriorityGroup.Normal)]
public partial class NormalEventHandler : IEventHandler<CriticalEvent>
{
public void Handle(CriticalEvent e)
{
// 处理普通逻辑
}
}
// 日志记录器最后执行
[Priority(PriorityGroup.Deferred)]
public partial class EventLogger : IEventHandler<CriticalEvent>
{
public void Handle(CriticalEvent e)
{
// 记录日志
}
}
事件总线按优先级调用处理器:
public class EventBus : IEventBus
{
public void Send<TEvent>(TEvent e) where TEvent : IEvent
{
// 获取所有处理器并按优先级排序
var handlers = this.GetAllByPriority<IEventHandler<TEvent>>();
foreach (var handler in handlers)
{
handler.Handle(e);
}
}
}
服务排序
控制多个服务实现的优先级:
// 高优先级服务
[Priority(PriorityGroup.High)]
public partial class PremiumService : IService
{
public void Execute()
{
// 优先执行
}
}
// 默认服务
[Priority(PriorityGroup.Normal)]
public partial class DefaultService : IService
{
public void Execute()
{
// 默认执行
}
}
// 后备服务
[Priority(PriorityGroup.Low)]
public partial class FallbackService : IService
{
public void Execute()
{
// 最后备选
}
}
与 PriorityUsageAnalyzer 集成
GF_Priority_Usage_001 诊断
PriorityUsageAnalyzer 分析器会检测应该使用 GetAllByPriority<T>() 而非 GetAll<T>() 的场景:
错误示例:
// ❌ 不推荐:可能未按优先级排序
var systems = context.GetAll<ISystem>();
正确示例:
// ✅ 推荐:确保按优先级排序
var systems = context.GetAllByPriority<ISystem>();
分析器规则
当满足以下条件时,分析器会报告 GF_Priority_Usage_001 诊断:
- 类型实现了
IPrioritized接口 - 使用了
GetAll<T>()方法 - 建议改用
GetAllByPriority<T>()方法
诊断信息
GF_Priority_001 - 只能应用于类
错误信息:Priority attribute can only be applied to classes
场景:将 [Priority] 特性应用于非类类型
[Priority(10)]
public interface IMyInterface // ❌ 错误
{
}
[Priority(10)]
public struct MyStruct // ❌ 错误
{
}
解决方案:只在类上使用 [Priority] 特性
[Priority(10)]
public partial class MyClass // ✅ 正确
{
}
GF_Priority_002 - 已实现 IPrioritized 接口
错误信息:Type '{ClassName}' already implements IPrioritized interface
场景:类已手动实现 IPrioritized 接口
[Priority(10)]
public partial class MySystem : IPrioritized // ❌ 冲突
{
public int Priority => 10; // 手动实现
}
解决方案:移除 [Priority] 特性或移除手动实现
// 方案1:移除特性,使用手动实现
public partial class MySystem : IPrioritized
{
public int Priority => 10;
}
// 方案2:移除手动实现,使用生成器
[Priority(10)]
public partial class MySystem
{
// 生成器自动实现
}
GF_Priority_003 - 必须声明为 partial
错误信息:Class '{ClassName}' must be declared as partial
场景:类未声明为 partial
[Priority(10)]
public class MySystem // ❌ 缺少 partial
{
}
解决方案:添加 partial 关键字
[Priority(10)]
public partial class MySystem // ✅ 正确
{
}
GF_Priority_004 - 优先级值无效
错误信息:Priority value is invalid
场景:特性参数无效或未提供
[Priority] // ❌ 缺少参数
public partial class MySystem
{
}
解决方案:提供有效的优先级值
[Priority(10)] // ✅ 正确
public partial class MySystem
{
}
GF_Priority_005 - 不支持嵌套类
错误信息:Nested class '{ClassName}' is not supported
场景:在嵌套类中使用 [Priority] 特性
public partial class OuterClass
{
[Priority(10)]
public partial class InnerClass // ❌ 错误
{
}
}
解决方案:将嵌套类提取为独立的类
[Priority(10)]
public partial class InnerClass // ✅ 正确
{
}
最佳实践
1. 使用 PriorityGroup 常量
避免使用魔法数字,优先使用预定义常量:
// ✅ 推荐:使用常量
[Priority(PriorityGroup.Critical)]
public partial class InputSystem { }
// ❌ 不推荐:魔法数字
[Priority(-100)]
public partial class InputSystem { }
2. 预留优先级间隔
为未来扩展预留间隔:
public static class SystemPriority
{
public const int Input = -100;
public const int PrePhysics = -90; // 预留扩展
public const int Physics = -80;
public const int PostPhysics = -70; // 预留扩展
public const int Gameplay = 0;
public const int PostGameplay = 10; // 预留扩展
public const int Audio = 50;
public const int Cleanup = 100;
}
3. 文档化优先级语义
为自定义优先级值添加注释:
/// <summary>
/// 输入系统,优先级 -100,需要最先初始化以接收输入事件
/// </summary>
[Priority(PriorityGroup.Critical)]
public partial class InputSystem : AbstractSystem
{
}
4. 避免优先级冲突
当多个类有相同优先级时,执行顺序不确定。应避免依赖特定顺序:
// ❌ 不推荐:相同优先级,顺序不确定
[Priority(0)]
public partial class SystemA { }
[Priority(0)]
public partial class SystemB { }
// ✅ 推荐:明确区分优先级
[Priority(-10)]
public partial class SystemA { }
[Priority(0)]
public partial class SystemB { }
5. 只在真正需要排序的场景使用
不要滥用优先级特性,只在确实需要排序的场景使用:
// ✅ 推荐:需要排序的系统
[Priority(PriorityGroup.Critical)]
public partial class InputSystem : AbstractSystem { }
// ❌ 不推荐:不需要排序的工具类
[Priority(10)]
public static partial class MathHelper // 静态工具类无需优先级
{
public static int Add(int a, int b) => a + b;
}
高级场景
泛型类支持
Priority 特性支持泛型类:
[Priority(20)]
public partial class GenericSystem<T> : ISystem
{
public void Init()
{
// 泛型系统的初始化
}
}
与其他特性组合
Priority 可以与其他源代码生成器特性组合使用:
using GFramework.SourceGenerators.Abstractions.Bases;
using GFramework.SourceGenerators.Abstractions.Logging;
using GFramework.SourceGenerators.Abstractions.Rule;
[Priority(PriorityGroup.High)]
[Log]
[ContextAware]
public partial class HighPrioritySystem : AbstractSystem
{
protected override void OnInit()
{
Logger.Info("High priority system initialized");
}
}
运行时优先级查询
可以在运行时查询优先级值:
public void ProcessSystems()
{
var systems = this.GetAllByPriority<ISystem>();
foreach (var system in systems)
{
if (system is IPrioritized prioritized)
{
Console.WriteLine($"System: {system.GetType().Name}, Priority: {prioritized.Priority}");
}
system.Init();
}
}
常见问题
Q: 优先级值可以是任意整数吗?
A: 是的,优先级值可以是任何 int 类型的值。推荐使用 PriorityGroup 预定义常量或在项目中定义自己的优先级常量。
Q: 多个类有相同优先级会怎样?
A: 当多个类有相同的优先级值时,它们的相对顺序是不确定的。建议为每个类设置不同的优先级值,或在文档中明确说明相同优先级类的执行顺序不保证。
Q: 可以在运行时改变优先级吗?
A: 不可以。Priority 属性是只读的,值在编译时确定。如果需要运行时改变优先级,应手动实现 IPrioritized 接口。
public class DynamicPrioritySystem : IPrioritized
{
private int _priority;
public int Priority => _priority;
public void SetPriority(int value)
{
_priority = value;
}
}
Q: 优先级支持继承吗?
A: [Priority] 特性标记为 Inherited = false,不会被子类继承。每个子类需要独立标记优先级。
[Priority(10)]
public partial class BaseSystem { }
public partial class DerivedSystem : BaseSystem // 不会继承 Priority = 10
{
// 需要重新标记
// [Priority(20)]
}
Q: 如何在不使用特性的情况下实现优先级?
A: 可以手动实现 IPrioritized 接口:
public class ManualPrioritySystem : IPrioritized
{
public int Priority => 10;
// 手动实现提供更大的灵活性
public int Priority => _config.Enabled ? 10 : 100;
}
Q: 负数优先级和正数优先级的区别是什么?
A: 优先级值用于排序,通常值越小优先级越高:
- 负数(-100):高优先级,最先执行
- 零(0):默认优先级
- 正数(100):低优先级,最后执行
具体含义取决于使用场景,但推荐遵循 PriorityGroup 定义的语义。
实际应用示例
游戏系统架构
完整的游戏系统初始化示例:
using GFramework.Core.Abstractions.Systems;
using GFramework.SourceGenerators.Abstractions.Bases;
using GFramework.Core.Abstractions.Bases;
// 输入系统(最先初始化)
[Priority(PriorityGroup.Critical)]
[Log]
public partial class InputSystem : AbstractSystem
{
protected override void OnInit()
{
Logger.Info("Input system initialized");
}
}
// 物理系统
[Priority(PriorityGroup.High)]
[Log]
public partial class PhysicsSystem : AbstractSystem
{
protected override void OnInit()
{
Logger.Info("Physics system initialized");
}
}
// 游戏逻辑系统
[Priority(PriorityGroup.Normal)]
[Log]
[ContextAware]
public partial class GameplaySystem : AbstractSystem
{
protected override void OnInit()
{
Logger.Info("Gameplay system initialized");
}
}
// 音频系统
[Priority(PriorityGroup.Low)]
[Log]
public partial class AudioSystem : AbstractSystem
{
protected override void OnInit()
{
Logger.Info("Audio system initialized");
}
}
// 清理系统(最后执行)
[Priority(PriorityGroup.Deferred)]
[Log]
public partial class CleanupSystem : AbstractSystem
{
protected override void OnInit()
{
Logger.Info("Cleanup system initialized");
}
}
在架构中初始化:
public class GameArchitecture : Architecture
{
protected override async Task InitAsync()
{
// 获取所有系统并按优先级排序
var systems = this.GetAllByPriority<ISystem>();
foreach (var system in systems)
{
await system.InitAsync();
}
}
}