docs: 更新源生成器文档并调整配置

- 移除 .claude 设置文件
- 重构枚举扩展生成器文档,更新 API 使用方式和配置选项
- 调整日志生成器文档,更新属性使用方式和配置参数
- 修改 Git 忽略规则添加 .claude/settings.json
- 更新代码示例和最佳实践指南
This commit is contained in:
GeWuYou 2026-03-07 23:13:21 +08:00
parent 4804b75215
commit 740cc66ac4
5 changed files with 450 additions and 344 deletions

View File

@ -1,5 +0,0 @@
{
"enabledPlugins": {
"oh-my-claudecode@omc": true
}
}

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ GFramework.sln.DotSettings.user
# ai # ai
opencode.json opencode.json
.claude/settings.local.json .claude/settings.local.json
.claude/settings.json
.omc/ .omc/
docs/.omc/ docs/.omc/
docs/.vitepress/cache/ docs/.vitepress/cache/

View File

@ -1,172 +1,235 @@
# 枚举扩展生成器 # 枚举扩展生成器
> GFramework.SourceGenerators 自动生成枚举扩展方法 > 自动为枚举类型生成扩展方法
## 概述 ## 概述
枚举扩展生成器为枚举类型自动生成常用的扩展方法,如获取描述、转换为字符串、解析等。这大大简化了枚举的操作。 枚举扩展生成器为标记了 `[GenerateEnumExtensions]` 属性的枚举自动生成两种扩展方法:
## 基本用法 1. **IsX 方法**:为每个枚举值生成判断方法
2. **IsIn 方法**:判断枚举值是否在指定集合中
### 标记枚举 ## 基础使用
```csharp ```csharp
using GFramework.SourceGenerators.Attributes; using GFramework.SourceGenerators.Abstractions.enums;
[EnumExtensions] [GenerateEnumExtensions]
public enum GameState
{
Normal,
Paused,
GameOver
}
```
## 生成的代码
编译器会自动生成如下扩展方法:
```csharp
// <auto-generated/>
public static class GameStateExtensions
{
// 为每个枚举值生成 IsX 方法
public static bool IsNormal(this GameState value)
=> value == GameState.Normal;
public static bool IsPaused(this GameState value)
=> value == GameState.Paused;
public static bool IsGameOver(this GameState value)
=> value == GameState.GameOver;
// 生成 IsIn 方法
public static bool IsIn(this GameState value, params GameState[] values)
{
if (values == null) return false;
foreach (var v in values) if (value == v) return true;
return false;
}
}
```
## 使用示例
```csharp
var state = GameState.Paused;
// 使用 IsX 方法
if (state.IsPaused())
{
Console.WriteLine("游戏已暂停");
}
// 使用 IsIn 方法
if (state.IsIn(GameState.Paused, GameState.GameOver))
{
Console.WriteLine("游戏未在运行中");
}
```
## 配置选项
可以通过属性参数控制生成行为:
```csharp
[GenerateEnumExtensions(
GenerateIsMethods = true, // 是否生成 IsX 方法(默认 true
GenerateIsInMethod = true // 是否生成 IsIn 方法(默认 true
)]
public enum GameState
{
Normal,
Paused,
GameOver
}
```
### 只生成 IsX 方法
```csharp
[GenerateEnumExtensions(GenerateIsInMethod = false)]
public enum GameState
{
Normal,
Paused
}
// 只生成 IsNormal() 和 IsPaused(),不生成 IsIn()
```
### 只生成 IsIn 方法
```csharp
[GenerateEnumExtensions(GenerateIsMethods = false)]
public enum GameState
{
Normal,
Paused
}
// 只生成 IsIn(),不生成 IsNormal() 和 IsPaused()
```
## 最佳实践
### 1. 命名约定
生成的方法名基于枚举值名称:
- `Normal``IsNormal()`
- `GameOver``IsGameOver()`
- `HTTP_ERROR``IsHTTP_ERROR()`
### 2. 性能考虑
生成的方法是内联的,性能与手写代码相同:
```csharp
// 生成的代码
public static bool IsNormal(this GameState value)
=> value == GameState.Normal;
// 等价于手写
if (state == GameState.Normal) { }
```
### 3. 可读性提升
```csharp
// 使用生成的方法(推荐)
if (state.IsPaused())
{
ResumeGame();
}
// 直接比较(不推荐)
if (state == GameState.Paused)
{
ResumeGame();
}
```
## 实际应用示例
### 游戏状态管理
```csharp
[GenerateEnumExtensions]
public enum GameState
{
MainMenu,
Playing,
Paused,
GameOver,
Victory
}
public class GameManager
{
private GameState _currentState = GameState.MainMenu;
public bool CanProcessInput()
{
// 使用 IsIn 方法简化多值判断
return _currentState.IsIn(GameState.Playing, GameState.MainMenu);
}
public void Update()
{
// 使用 IsX 方法提高可读性
if (_currentState.IsPlaying())
{
UpdateGameLogic();
}
else if (_currentState.IsPaused())
{
UpdatePauseMenu();
}
}
}
```
### 角色状态控制
```csharp
[GenerateEnumExtensions]
public enum PlayerState public enum PlayerState
{ {
Idle, Idle,
Walking,
Running, Running,
Jumping, Jumping,
Attacking Attacking
} }
```
### 生成的方法 public class PlayerController
上面的代码会被转换为:
```csharp
public static class PlayerStateExtensions
{ {
public static string GetDescription(this PlayerState value) private PlayerState _state = PlayerState.Idle;
public bool CanAttack()
{ {
// 返回枚举的描述 // 清晰表达可以攻击的状态
return _state.IsIn(PlayerState.Idle, PlayerState.Walking, PlayerState.Running);
} }
public static bool HasFlag(this PlayerState value, PlayerState flag) public void HandleInput(string action)
{ {
// 检查是否包含标志 if (action == "jump" && !_state.IsJumping())
{
_state = PlayerState.Jumping;
} }
public static PlayerState FromString(string value)
{
// 从字符串解析枚举
} }
} }
``` ```
## 常用方法 ## 限制
### 获取描述 1. **只支持枚举类型**:不能用于类或结构体
2. **不支持 Flags 枚举的特殊处理**:对于 `[Flags]` 枚举,生成的方法仍然是简单的相等比较
3. **不生成其他方法**:只生成 IsX 和 IsIn 方法
```csharp ## 相关文档
[EnumExtensions]
public enum ItemQuality
{
[Description("普通")]
Common,
[Description("稀有")]
Rare,
[Description("史诗")]
Epic
}
public void PrintQuality(ItemQuality quality)
{
// 获取描述文本
Console.WriteLine(quality.GetDescription());
// 输出: "普通" / "稀有" / "史诗"
}
```
### 安全解析
```csharp
public void ParseState(string input)
{
// 安全地解析字符串为枚举
if (PlayerState.Running.TryParse(input, out var state))
{
Console.WriteLine($"状态: {state}");
}
}
```
### 获取所有值
```csharp
public void ListAllStates()
{
// 获取所有枚举值
foreach (var state in PlayerState.GetAllValues())
{
Console.WriteLine(state);
}
}
```
## 标志枚举
对于使用 `[Flags]` 特性的枚举:
```csharp
[EnumExtensions]
[Flags]
public enum PlayerPermissions
{
None = 0,
Read = 1,
Write = 2,
Execute = 4,
All = Read | Write | Execute
}
public void CheckPermissions()
{
var permissions = PlayerPermissions.Read | PlayerPermissions.Write;
// 检查是否包含特定权限
if (permissions.HasFlag(PlayerPermissions.Write))
{
Console.WriteLine("有写入权限");
}
// 获取所有设置的标志
foreach (var flag in permissions.GetFlags())
{
Console.WriteLine($"权限: {flag}");
}
}
```
## 自定义行为
### 忽略某些值
```csharp
[EnumExtensions(IgnoreValues = new[] { ItemQuality.Undefined })]
public enum ItemQuality
{
Undefined,
Common,
Rare,
Epic
}
// GetAllValues() 不会返回 Undefined
```
### 自定义转换
```csharp
[EnumExtensions(CaseSensitive = false)]
public enum Difficulty
{
Easy,
Medium,
Hard
}
// FromString("EASY") 也能正确解析
```
---
**相关文档**
- [Source Generators 概述](./index) - [Source Generators 概述](./index)
- [日志生成器](./logging-generator) - [日志生成器](./logging-generator)

View File

@ -107,33 +107,29 @@ public partial class PlayerController
```csharp ```csharp
// <auto-generated/> // <auto-generated/>
using Microsoft.Extensions.Logging;
namespace YourNamespace
{
public partial class PlayerController public partial class PlayerController
{ {
private static readonly ILogger Logger = private static readonly ILogger Logger =
LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger<PlayerController>(); LoggerFactoryResolver.Provider.CreateLogger("YourNamespace.PlayerController");
}
} }
``` ```
**注意**:生成器只生成 ILogger 字段不生成日志方法。日志方法Info、Debug、Error 等)来自 ILogger 接口本身。
### 高级配置 ### 高级配置
```csharp ```csharp
[Log( [Log(
fieldName = "CustomLogger", // 自定义字段名 Name = "Custom.PlayerLogger", // 自定义日志分类名称
accessModifier = AccessModifier.Public, // 访问修饰符 FieldName = "CustomLogger", // 自定义字段名
isStatic = false, // 是否为静态字段 IsStatic = false, // 是否为静态字段
loggerName = "Custom.PlayerLogger", // 自定义日志器名称 AccessModifier = "public" // 访问修饰符
includeLoggerInterface = true // 是否包含 ILogger 接口
)] )]
public partial class CustomLoggerExample public partial class CustomLoggerExample
{ {
public void LogSomething() public void LogSomething()
{ {
CustomLogger.LogInformation("Custom logger message"); CustomLogger.Info("Custom logger message");
} }
} }
``` ```
@ -141,12 +137,11 @@ public partial class CustomLoggerExample
### 配置选项说明 ### 配置选项说明
| 参数 | 类型 | 默认值 | 说明 | | 参数 | 类型 | 默认值 | 说明 |
|--------------------------|----------------|----------|---------------------| |----------------|---------|-----------|---------------------------------|
| `fieldName` | string | "Logger" | 生成的日志字段名称 | | Name | string? | null | 日志分类名称(默认使用类名) |
| `accessModifier` | AccessModifier | Private | 字段访问修饰符 | | FieldName | string | "Logger" | 生成的字段名称 |
| `isStatic` | bool | true | 是否生成静态字段 | | IsStatic | bool | true | 是否生成静态字段 |
| `loggerName` | string | null | 自定义日志器名称null 时使用类名 | | AccessModifier | string | "private" | 访问修饰符private/protected/public |
| `includeLoggerInterface` | bool | false | 是否包含 ILogger 接口实现 |
### 静态类支持 ### 静态类支持
@ -162,21 +157,6 @@ public static partial class MathHelper
} }
``` ```
### 日志级别控制
```csharp
[Log(minLevel = LogLevel.Warning)]
public partial class WarningOnlyLogger
{
public void ProcessData()
{
Logger.Debug("This won't be logged"); // 低于最小级别,被过滤
Logger.Warning("This will be logged");
Logger.Error("This will also be logged");
}
}
```
## ContextAware 属性生成器 ## ContextAware 属性生成器
[ContextAware] 属性自动实现 IContextAware 接口,提供便捷的架构上下文访问能力。 [ContextAware] 属性自动实现 IContextAware 接口,提供便捷的架构上下文访问能力。
@ -316,7 +296,7 @@ public partial class AdvancedController : IController
### 基础使用 ### 基础使用
```csharp ```csharp
using GFramework.SourceGenerators.Attributes; using GFramework.SourceGenerators.Abstractions.enums;
[GenerateEnumExtensions] [GenerateEnumExtensions]
public enum GameState public enum GameState
@ -337,7 +317,9 @@ public static class GameStateExtensions
public static bool IsIn(this GameState state, params GameState[] values) public static bool IsIn(this GameState state, params GameState[] values)
{ {
return values.Contains(state); if (values == null) return false;
foreach (var v in values) if (state == v) return true;
return false;
} }
} }
@ -363,15 +345,12 @@ public class GameManager
} }
``` ```
### 自定义扩展方法 ### 配置选项
```csharp ```csharp
[GenerateEnumExtensions( [GenerateEnumExtensions(
generateIsMethods = true, GenerateIsMethods = true, // 是否生成 IsX 方法(默认 true
generateHasMethod = true, GenerateIsInMethod = true // 是否生成 IsIn 方法(默认 true
generateInMethod = true,
customPrefix = "Is",
includeToString = true
)] )]
public enum PlayerState public enum PlayerState
{ {
@ -381,84 +360,14 @@ public enum PlayerState
Jumping, Jumping,
Attacking Attacking
} }
// 生成更多扩展方法
public static class PlayerStateExtensions
{
public static bool IsIdle(this PlayerState state) => state == PlayerState.Idle;
public static bool IsWalking(this PlayerState state) => state == PlayerState.Walking;
public static bool IsRunning(this PlayerState state) => state == PlayerState.Running;
public static bool IsJumping(this PlayerState state) => state == PlayerState.Jumping;
public static bool IsAttacking(this PlayerState state) => state == PlayerState.Attacking;
public static bool HasIdle(this PlayerState state) => state == PlayerState.Idle;
public static bool HasWalking(this PlayerState state) => state == PlayerState.Walking;
// ... 其他 Has 方法
public static bool In(this PlayerState state, params PlayerState[] values)
{
return values.Contains(state);
}
public static string ToDisplayString(this PlayerState state)
{
return state switch
{
PlayerState.Idle => "Idle",
PlayerState.Walking => "Walking",
PlayerState.Running => "Running",
PlayerState.Jumping => "Jumping",
PlayerState.Attacking => "Attacking",
_ => state.ToString()
};
}
}
```
### 位标志枚举支持
```csharp
[GenerateEnumExtensions]
[Flags]
public enum PlayerAbilities
{
None = 0,
Jump = 1 << 0,
Run = 1 << 1,
Attack = 1 << 2,
Defend = 1 << 3,
Magic = 1 << 4
}
// 生成位标志扩展方法
public static class PlayerAbilitiesExtensions
{
public static bool HasJump(this PlayerAbilities abilities) => abilities.HasFlag(PlayerAbilities.Jump);
public static bool HasRun(this PlayerAbilities abilities) => abilities.HasFlag(PlayerAbilities.Run);
// ... 其他位标志方法
public static bool HasAny(this PlayerAbilities abilities, params PlayerAbilities[] flags)
{
return flags.Any(flag => abilities.HasFlag(flag));
}
public static bool HasAll(this PlayerAbilities abilities, params PlayerAbilities[] flags)
{
return flags.All(flag => abilities.HasFlag(flag));
}
}
``` ```
### 配置选项说明 ### 配置选项说明
| 参数 | 类型 | 默认值 | 说明 | | 参数 | 类型 | 默认值 | 说明 |
|---------------------|--------|-------|------------------------| |--------------------|------|------|-------------------|
| `generateIsMethods` | bool | true | 是否生成 IsX() 方法 | | GenerateIsMethods | bool | true | 是否为每个枚举值生成 IsX 方法 |
| `generateHasMethod` | bool | true | 是否生成 HasX() 方法 | | GenerateIsInMethod | bool | true | 是否生成 IsIn 方法 |
| `generateInMethod` | bool | true | 是否生成 In(params T[]) 方法 |
| `customPrefix` | string | "Is" | 方法名前缀 |
| `includeToString` | bool | false | 是否生成 ToString 扩展 |
| `namespace` | string | null | 生成扩展类的命名空间 |
## 诊断信息 ## 诊断信息
@ -839,7 +748,7 @@ public enum State
```csharp ```csharp
// 好的做法:合理的日志级别 // 好的做法:合理的日志级别
[Log(minLevel = LogLevel.Information)] [Log]
public partial class PerformanceCriticalComponent public partial class PerformanceCriticalComponent
{ {
public void Update() public void Update()
@ -853,7 +762,7 @@ public partial class PerformanceCriticalComponent
} }
// 避免:过度日志记录 // 避免:过度日志记录
[Log(minLevel = LogLevel.Debug)] [Log]
public partial class NoisyComponent public partial class NoisyComponent
{ {
public void Update() public void Update()
@ -863,47 +772,8 @@ public partial class NoisyComponent
} }
``` ```
#### 2. 延迟上下文初始化
```csharp
// 好的做法:延迟初始化
[ContextAware(useLazy = true)]
public partial class LazyContextComponent : IComponent
{
// 只有在第一次访问 Context 时才会初始化
public void Initialize()
{
// 如果这里不需要 Context就不会初始化
SomeOtherInitialization();
}
}
```
### 🛡️ 错误处理 ### 🛡️ 错误处理
#### 1. 上下文验证
```csharp
[ContextAware(validateContext = true)]
public partial class SafeContextComponent : IComponent
{
public void ProcessData()
{
if (Context.IsInvalid)
{
Logger.Error("Context is invalid, cannot process data");
return;
}
// 安全地使用 Context
var model = Context.GetModel<DataModel>();
// ...
}
}
```
#### 2. 异常处理配合
```csharp ```csharp
[Log] [Log]
[ContextAware] [ContextAware]

View File

@ -4,22 +4,21 @@
## 概述 ## 概述
日志生成器是一个 Source Generator它会自动为标记了 `[Log]` 特性的类生成 Logger 字段和日志方法调用。这消除了手动编写日志代码的需要,让开发者专注于业务逻辑。 日志生成器是一个 Source Generator它会自动为标记了 `[Log]` 特性的类生成 ILogger 字段。这消除了手动编写日志字段的需要,让开发者专注于业务逻辑。
## 基本用法 ## 基本用法
### 标记类 ### 标记类
```csharp ```csharp
using GFramework.SourceGenerators.Attributes; using GFramework.SourceGenerators.Abstractions.logging;
[Log] [Log]
public partial class MyService public partial class MyService
{ {
public void DoSomething() public void DoSomething()
{ {
// 自动生成 Logger 字段 // 自动生成的 Logger 字段可直接使用
// 自动生成日志调用
Logger.Info("执行操作"); Logger.Info("执行操作");
} }
} }
@ -30,31 +29,19 @@ public partial class MyService
上面的代码会被编译时转换为: 上面的代码会被编译时转换为:
```csharp ```csharp
// <auto-generated/>
public partial class MyService public partial class MyService
{ {
// 自动生成的字段 private static readonly ILogger Logger =
[CompilerGenerated] LoggerFactoryResolver.Provider.CreateLogger("YourNamespace.MyService");
private ILogger _logger;
// 自动生成的属性
[CompilerGenerated]
public ILogger Logger
{
get
{
if (_logger == null)
{
_logger = LoggerFactory.CreateLogger<MyService>();
}
return _logger;
}
}
} }
``` ```
**注意**:生成器只生成 ILogger 字段不生成日志方法。日志方法Info、Debug、Error 等)来自 ILogger 接口本身。
## 日志级别 ## 日志级别
生成的日志方法支持多种级别 生成的 Logger 字段支持 ILogger 接口的所有方法:
```csharp ```csharp
[Log] [Log]
@ -83,7 +70,7 @@ public partial class MyClass
## 自定义日志类别 ## 自定义日志类别
```csharp ```csharp
[Log(LogCategory.Gameplay)] [Log("Gameplay")]
public partial class GameplaySystem public partial class GameplaySystem
{ {
// 日志会标记为 Gameplay 类别 // 日志会标记为 Gameplay 类别
@ -94,6 +81,55 @@ public partial class GameplaySystem
} }
``` ```
## 配置选项
### 自定义字段名称
```csharp
[Log(FieldName = "_customLogger")]
public partial class MyClass
{
public void DoSomething()
{
// 使用自定义字段名
_customLogger.Info("使用自定义日志器");
}
}
```
### 非静态字段
```csharp
[Log(IsStatic = false)]
public partial class InstanceLogger
{
// 生成实例字段而非静态字段
public void LogMessage()
{
Logger.Info("实例日志");
}
}
```
### 访问修饰符
```csharp
[Log(AccessModifier = "protected")]
public partial class ProtectedLogger
{
// 生成 protected 字段
}
```
### 配置选项说明
| 参数 | 类型 | 默认值 | 说明 |
|----------------|---------|-----------|---------------------------------|
| Name | string? | null | 日志分类名称(默认使用类名) |
| FieldName | string | "Logger" | 生成的字段名称 |
| IsStatic | bool | true | 是否生成静态字段 |
| AccessModifier | string | "private" | 访问修饰符private/protected/public |
## 与其他模块集成 ## 与其他模块集成
### 与 Godot 集成 ### 与 Godot 集成
@ -123,34 +159,175 @@ public partial class MySystem : AbstractSystem
} }
``` ```
## 配置选项 ## 实际应用示例
### 禁用自动生成 ### 游戏控制器
```csharp ```csharp
// 禁用自动日志调用生成 [Log]
[Log(AutoLog = false)] [ContextAware]
public partial class MyClass public partial class PlayerController : IController
{ {
// 仍会生成 Logger 字段,但不会自动生成日志调用 public void HandleInput(string action)
public void DoSomething()
{ {
// 需要手动调用 Logger Logger.Debug($"处理输入: {action}");
Logger.Info("手动日志");
switch (action)
{
case "jump":
Logger.Info("玩家跳跃");
Jump();
break;
case "attack":
Logger.Info("玩家攻击");
Attack();
break;
default:
Logger.Warning($"未知操作: {action}");
break;
}
}
private void Jump()
{
try
{
// 跳跃逻辑
Logger.Debug("跳跃执行成功");
}
catch (Exception ex)
{
Logger.Error($"跳跃失败: {ex.Message}");
}
} }
} }
``` ```
### 自定义字段名称 ### 数据处理服务
```csharp ```csharp
[Log(FieldName = "_customLogger")] [Log("DataService")]
public partial class MyClass public partial class DataProcessor
{ {
// Logger 字段名称为 _customLogger public void ProcessData(string data)
{
Logger.Info($"开始处理数据,长度: {data.Length}");
if (string.IsNullOrEmpty(data))
{
Logger.Warning("数据为空,跳过处理");
return;
}
try
{
// 处理逻辑
Logger.Debug("数据处理中...");
// ...
Logger.Info("数据处理完成");
}
catch (Exception ex)
{
Logger.Error($"数据处理失败: {ex.Message}");
throw;
}
}
} }
``` ```
## 最佳实践
### 1. 合理使用日志级别
```csharp
[Log]
public partial class BestPracticeExample
{
public void ProcessRequest()
{
// Debug: 详细的调试信息
Logger.Debug("开始处理请求");
// Info: 重要的业务流程信息
Logger.Info("请求处理成功");
// Warning: 可恢复的异常情况
Logger.Warning("缓存未命中,使用默认值");
// Error: 错误但不影响系统运行
Logger.Error("处理失败,将重试");
// Critical: 严重错误,可能导致系统崩溃
Logger.Critical("数据库连接失败");
}
}
```
### 2. 避免过度日志
```csharp
[Log]
public partial class PerformanceExample
{
private int _frameCount = 0;
public void Update()
{
// 好的做法:定期记录
if (_frameCount % 1000 == 0)
{
Logger.Debug($"已运行 {_frameCount} 帧");
}
_frameCount++;
// 避免:每帧都记录
// Logger.Debug($"帧 {_frameCount}"); // ❌ 太频繁
}
}
```
### 3. 结构化日志信息
```csharp
[Log]
public partial class StructuredLogging
{
public void ProcessUser(int userId, string action)
{
// 好的做法:包含上下文信息
Logger.Info($"用户操作 [UserId={userId}, Action={action}]");
// 避免:信息不完整
// Logger.Info("用户操作"); // ❌ 缺少上下文
}
}
```
## 常见问题
### Q: 为什么需要 partial 关键字?
**A**: 源代码生成器需要向现有类添加代码,`partial` 关键字允许一个类的定义分散在多个文件中。
### Q: 可以在静态类中使用吗?
**A**: 可以,生成器会自动生成静态字段:
```csharp
[Log]
public static partial class StaticHelper
{
public static void DoSomething()
{
Logger.Info("静态方法日志");
}
}
```
### Q: 如何自定义日志工厂?
**A**: 通过配置 `LoggerFactoryResolver.Provider` 来自定义日志工厂实现。
--- ---
**相关文档** **相关文档**