mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 13:33:28 +08:00
docs(guide): 添加 ContextAware 生成器文档并更新相关链接
- 新增 ContextAware 生成器完整文档,介绍自动实现 IContextAware 接口的功能 - 更新索引页面中的相关链接,替换规则生成器为 ContextAware 生成器 - 修改基础使用示例中的命名空间引用和代码实现细节 - 补充测试场景配置和多架构场景的使用说明 - 添加最佳实践和诊断信息相关内容
This commit is contained in:
parent
575dcdf27b
commit
6d398a515b
378
docs/zh-CN/source-generators/context-aware-generator.md
Normal file
378
docs/zh-CN/source-generators/context-aware-generator.md
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
# ContextAware 生成器
|
||||||
|
|
||||||
|
> 自动实现 IContextAware 接口,提供架构上下文访问能力
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
ContextAware 生成器为标记了 `[ContextAware]` 属性的类自动生成 `IContextAware` 接口实现,使类能够便捷地访问架构上下文(
|
||||||
|
`IArchitectureContext`)。这是 GFramework 中最常用的源码生成器之一,几乎所有需要与架构交互的组件都会使用它。
|
||||||
|
|
||||||
|
### 核心功能
|
||||||
|
|
||||||
|
- **自动接口实现**:无需手动实现 `IContextAware` 接口的 `SetContext()` 和 `GetContext()` 方法
|
||||||
|
- **懒加载上下文**:`Context` 属性在首次访问时自动初始化
|
||||||
|
- **默认提供者**:使用 `GameContextProvider` 作为默认上下文提供者
|
||||||
|
- **测试友好**:支持通过 `SetContextProvider()` 配置自定义上下文提供者
|
||||||
|
|
||||||
|
## 基础使用
|
||||||
|
|
||||||
|
### 标记类
|
||||||
|
|
||||||
|
使用 `[ContextAware]` 属性标记需要访问架构上下文的类:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.SourceGenerators.Abstractions.rule;
|
||||||
|
using GFramework.Core.Abstractions.controller;
|
||||||
|
|
||||||
|
[ContextAware]
|
||||||
|
public partial class PlayerController : IController
|
||||||
|
{
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
// Context 属性自动生成,提供架构上下文访问
|
||||||
|
var playerModel = Context.GetModel<PlayerModel>();
|
||||||
|
var combatSystem = Context.GetSystem<CombatSystem>();
|
||||||
|
|
||||||
|
Context.SendEvent(new PlayerInitializedEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Attack(Enemy target)
|
||||||
|
{
|
||||||
|
var damage = Context.GetUtility<DamageCalculator>().Calculate(this, target);
|
||||||
|
Context.SendCommand(new DealDamageCommand(target, damage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 必要条件
|
||||||
|
|
||||||
|
标记的类必须满足以下条件:
|
||||||
|
|
||||||
|
1. **必须是 `partial` 类**:生成器需要生成部分类代码
|
||||||
|
2. **必须是 `class` 类型**:不能是 `struct` 或 `interface`
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// ✅ 正确
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyController { }
|
||||||
|
|
||||||
|
// ❌ 错误:缺少 partial 关键字
|
||||||
|
[ContextAware]
|
||||||
|
public class MyController { }
|
||||||
|
|
||||||
|
// ❌ 错误:不能用于 struct
|
||||||
|
[ContextAware]
|
||||||
|
public partial struct MyStruct { }
|
||||||
|
```
|
||||||
|
|
||||||
|
## 生成的代码
|
||||||
|
|
||||||
|
编译器会为标记的类自动生成以下代码:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// <auto-generated/>
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace YourNamespace;
|
||||||
|
|
||||||
|
partial class PlayerController : global::GFramework.Core.Abstractions.rule.IContextAware
|
||||||
|
{
|
||||||
|
private global::GFramework.Core.Abstractions.architecture.IArchitectureContext? _context;
|
||||||
|
private static global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider? _contextProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider)
|
||||||
|
/// </summary>
|
||||||
|
protected global::GFramework.Core.Abstractions.architecture.IArchitectureContext Context
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_context == null)
|
||||||
|
{
|
||||||
|
_contextProvider ??= new global::GFramework.Core.architecture.GameContextProvider();
|
||||||
|
_context = _contextProvider.GetContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配置上下文提供者(用于测试或多架构场景)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="provider">上下文提供者实例</param>
|
||||||
|
public static void SetContextProvider(global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider provider)
|
||||||
|
{
|
||||||
|
_contextProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置上下文提供者为默认值(用于测试清理)
|
||||||
|
/// </summary>
|
||||||
|
public static void ResetContextProvider()
|
||||||
|
{
|
||||||
|
_contextProvider = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void global::GFramework.Core.Abstractions.rule.IContextAware.SetContext(global::GFramework.Core.Abstractions.architecture.IArchitectureContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
global::GFramework.Core.Abstractions.architecture.IArchitectureContext global::GFramework.Core.Abstractions.rule.IContextAware.GetContext()
|
||||||
|
{
|
||||||
|
return Context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码解析
|
||||||
|
|
||||||
|
生成的代码包含以下关键部分:
|
||||||
|
|
||||||
|
1. **私有字段**:
|
||||||
|
- `_context`:缓存的上下文实例
|
||||||
|
- `_contextProvider`:静态上下文提供者(所有实例共享)
|
||||||
|
|
||||||
|
2. **Context 属性**:
|
||||||
|
- `protected` 访问级别,子类可访问
|
||||||
|
- 懒加载:首次访问时自动初始化
|
||||||
|
- 使用 `GameContextProvider` 作为默认提供者
|
||||||
|
|
||||||
|
3. **配置方法**:
|
||||||
|
- `SetContextProvider()`:设置自定义上下文提供者
|
||||||
|
- `ResetContextProvider()`:重置为默认提供者
|
||||||
|
|
||||||
|
4. **显式接口实现**:
|
||||||
|
- `IContextAware.SetContext()`:允许外部设置上下文
|
||||||
|
- `IContextAware.GetContext()`:返回当前上下文
|
||||||
|
|
||||||
|
## 配置上下文提供者
|
||||||
|
|
||||||
|
### 测试场景
|
||||||
|
|
||||||
|
在单元测试中,通常需要使用自定义的上下文提供者:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Test]
|
||||||
|
public void TestPlayerController()
|
||||||
|
{
|
||||||
|
// 创建测试架构
|
||||||
|
var testArchitecture = new TestArchitecture();
|
||||||
|
await testArchitecture.InitAsync();
|
||||||
|
|
||||||
|
// 配置自定义上下文提供者
|
||||||
|
PlayerController.SetContextProvider(new TestContextProvider(testArchitecture));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 测试代码
|
||||||
|
var controller = new PlayerController();
|
||||||
|
controller.Initialize();
|
||||||
|
|
||||||
|
// 验证...
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 清理:重置上下文提供者
|
||||||
|
PlayerController.ResetContextProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 多架构场景
|
||||||
|
|
||||||
|
在某些高级场景中,可能需要同时运行多个架构实例:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class MultiArchitectureManager
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, IArchitecture> _architectures = new();
|
||||||
|
|
||||||
|
public void SwitchToArchitecture(string name)
|
||||||
|
{
|
||||||
|
var architecture = _architectures[name];
|
||||||
|
var provider = new ScopedContextProvider(architecture);
|
||||||
|
|
||||||
|
// 为所有使用 [ContextAware] 的类切换上下文
|
||||||
|
PlayerController.SetContextProvider(provider);
|
||||||
|
EnemyController.SetContextProvider(provider);
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用场景
|
||||||
|
|
||||||
|
### 何时使用 [ContextAware]
|
||||||
|
|
||||||
|
推荐在以下场景使用 `[ContextAware]` 属性:
|
||||||
|
|
||||||
|
1. **Controller 层**:需要协调多个 Model/System 的控制器
|
||||||
|
2. **Command/Query 实现**:需要访问架构服务的命令或查询
|
||||||
|
3. **自定义组件**:不继承框架基类但需要上下文访问的组件
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial class GameFlowController : IController
|
||||||
|
{
|
||||||
|
public async Task StartGame()
|
||||||
|
{
|
||||||
|
var saveSystem = Context.GetSystem<SaveSystem>();
|
||||||
|
var uiSystem = Context.GetSystem<UISystem>();
|
||||||
|
|
||||||
|
await saveSystem.LoadAsync();
|
||||||
|
await uiSystem.ShowMainMenuAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 何时继承 ContextAwareBase
|
||||||
|
|
||||||
|
如果类需要更多框架功能(如生命周期管理),应继承 `ContextAwareBase`:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 推荐:需要生命<E7949F><E591BD><EFBFBD>期管理时继承基类
|
||||||
|
public class PlayerModel : AbstractModel
|
||||||
|
{
|
||||||
|
// AbstractModel 已经继承了 ContextAwareBase
|
||||||
|
protected override void OnInit()
|
||||||
|
{
|
||||||
|
var config = Context.GetUtility<ConfigLoader>().Load<PlayerConfig>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推荐:简单组件使用属性
|
||||||
|
[ContextAware]
|
||||||
|
public partial class SimpleHelper
|
||||||
|
{
|
||||||
|
public void DoSomething()
|
||||||
|
{
|
||||||
|
Context.SendEvent(new SomethingHappenedEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与 IContextAware 接口的关系
|
||||||
|
|
||||||
|
生成的代码实现了 `IContextAware` 接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
namespace GFramework.Core.Abstractions.rule;
|
||||||
|
|
||||||
|
public interface IContextAware
|
||||||
|
{
|
||||||
|
void SetContext(IArchitectureContext context);
|
||||||
|
IArchitectureContext GetContext();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
这意味着标记了 `[ContextAware]` 的类可以:
|
||||||
|
|
||||||
|
1. **被架构自动注入上下文**:实现 `IContextAware` 的类在注册到架构时会自动调用 `SetContext()`
|
||||||
|
2. **参与依赖注入**:可以作为 `IContextAware` 类型注入到其他组件
|
||||||
|
3. **支持上下文传递**:可以通过 `GetContext()` 将上下文传递给其他组件
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 始终使用 partial 关键字
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// ✅ 正确
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyController { }
|
||||||
|
|
||||||
|
// ❌ 错误:编译器会报错
|
||||||
|
[ContextAware]
|
||||||
|
public class MyController { }
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 在测试中清理上下文提供者
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown()
|
||||||
|
{
|
||||||
|
// 避免测试之间的状态污染
|
||||||
|
PlayerController.ResetContextProvider();
|
||||||
|
EnemyController.ResetContextProvider();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 避免在构造函数中访问 Context
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyController
|
||||||
|
{
|
||||||
|
// ❌ 错误:构造函数执行时上下文可能未初始化
|
||||||
|
public MyController()
|
||||||
|
{
|
||||||
|
var model = Context.GetModel<SomeModel>(); // 可能为 null
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ 正确:在初始化方法中访问
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
var model = Context.GetModel<SomeModel>(); // 安全
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 优先使用 Context 属性而非接口方法
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyController
|
||||||
|
{
|
||||||
|
public void DoSomething()
|
||||||
|
{
|
||||||
|
// ✅ 推荐:使用生成的 Context 属性
|
||||||
|
var model = Context.GetModel<SomeModel>();
|
||||||
|
|
||||||
|
// ❌ 不推荐:显式调用接口方法
|
||||||
|
var context = ((IContextAware)this).GetContext();
|
||||||
|
var model2 = context.GetModel<SomeModel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 诊断信息
|
||||||
|
|
||||||
|
生成器会在以下情况报告编译错误:
|
||||||
|
|
||||||
|
### GFSG001: 类必须是 partial
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public class MyController { } // 错误:缺少 partial 关键字
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**:添加 `partial` 关键字
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyController { } // ✅ 正确
|
||||||
|
```
|
||||||
|
|
||||||
|
### GFSG002: ContextAware 只能用于类
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial struct MyStruct { } // 错误:不能用于 struct
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**:将 `struct` 改为 `class`
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyClass { } // ✅ 正确
|
||||||
|
```
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
- [Source Generators 概述](./index)
|
||||||
|
- [架构上下文](../core/context)
|
||||||
|
- [IContextAware 接口](../core/rule)
|
||||||
|
- [日志生成器](./logging-generator)
|
||||||
|
- [规则验证生成器](./rule-generator)
|
||||||
@ -170,4 +170,4 @@ public enum Difficulty
|
|||||||
|
|
||||||
- [Source Generators 概述](./index)
|
- [Source Generators 概述](./index)
|
||||||
- [日志生成器](./logging-generator)
|
- [日志生成器](./logging-generator)
|
||||||
- [规则生成器](./rule-generator)
|
- [ContextAware 生成器](./context-aware-generator)
|
||||||
|
|||||||
@ -184,8 +184,8 @@ public partial class WarningOnlyLogger
|
|||||||
### 基础使用
|
### 基础使用
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
using GFramework.SourceGenerators.Attributes;
|
using GFramework.SourceGenerators.Abstractions.rule;
|
||||||
using GFramework.Core.Abstractions;
|
using GFramework.Core.Abstractions.controller;
|
||||||
|
|
||||||
[ContextAware]
|
[ContextAware]
|
||||||
public partial class PlayerController : IController
|
public partial class PlayerController : IController
|
||||||
@ -207,57 +207,84 @@ public partial class PlayerController : IController
|
|||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
// <auto-generated/>
|
// <auto-generated/>
|
||||||
using GFramework.Core.Abstractions;
|
#nullable enable
|
||||||
|
|
||||||
namespace YourNamespace
|
namespace YourNamespace;
|
||||||
|
|
||||||
|
partial class PlayerController : global::GFramework.Core.Abstractions.rule.IContextAware
|
||||||
{
|
{
|
||||||
public partial class PlayerController : IContextAware
|
private global::GFramework.Core.Abstractions.architecture.IArchitectureContext? _context;
|
||||||
|
private static global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider? _contextProvider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自动获取的架构上下文(懒加载,默认使用 GameContextProvider)
|
||||||
|
/// </summary>
|
||||||
|
protected global::GFramework.Core.Abstractions.architecture.IArchitectureContext Context
|
||||||
{
|
{
|
||||||
private IContextAware.Context _context;
|
get
|
||||||
|
|
||||||
public IContextAware.Context Context => _context ??= new LazyContext(this);
|
|
||||||
|
|
||||||
public void SetContext(IContextAware.Context context)
|
|
||||||
{
|
{
|
||||||
_context = context;
|
if (_context == null)
|
||||||
}
|
{
|
||||||
|
_contextProvider ??= new global::GFramework.Core.architecture.GameContextProvider();
|
||||||
|
_context = _contextProvider.GetContext();
|
||||||
|
}
|
||||||
|
|
||||||
public IContextAware.Context GetContext()
|
|
||||||
{
|
|
||||||
return _context;
|
return _context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 延迟初始化
|
/// <summary>
|
||||||
|
/// 配置上下文提供者(用于测试或多架构场景)
|
||||||
```csharp
|
/// </summary>
|
||||||
[ContextAware(useLazy = true)]
|
public static void SetContextProvider(global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider provider)
|
||||||
public partial class LazyContextExample
|
|
||||||
{
|
|
||||||
public void AccessContext()
|
|
||||||
{
|
{
|
||||||
// Context 会延迟初始化,直到第一次访问
|
_contextProvider = provider;
|
||||||
var model = Context.GetModel<SomeModel>();
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置上下文提供者为默认值(用于测试清理)
|
||||||
|
/// </summary>
|
||||||
|
public static void ResetContextProvider()
|
||||||
|
{
|
||||||
|
_contextProvider = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void global::GFramework.Core.Abstractions.rule.IContextAware.SetContext(global::GFramework.Core.Abstractions.architecture.IArchitectureContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
global::GFramework.Core.Abstractions.architecture.IArchitectureContext global::GFramework.Core.Abstractions.rule.IContextAware.GetContext()
|
||||||
|
{
|
||||||
|
return Context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 上下文验证
|
### 测试场景配置
|
||||||
|
|
||||||
|
在单元测试中,可以配置自定义的上下文提供者:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
[ContextAware(validateContext = true)]
|
[Test]
|
||||||
public partial class ValidatedContextExample
|
public async Task TestPlayerController()
|
||||||
{
|
{
|
||||||
public void AccessContext()
|
var testArchitecture = new TestArchitecture();
|
||||||
|
await testArchitecture.InitAsync();
|
||||||
|
|
||||||
|
// 配置测试上下文提供者
|
||||||
|
PlayerController.SetContextProvider(new TestContextProvider(testArchitecture));
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// 每次访问都会验证上下文的有效性
|
var controller = new PlayerController();
|
||||||
var model = Context.GetModel<SomeModel>();
|
controller.Initialize();
|
||||||
if (Context.IsInvalid)
|
// 测试逻辑...
|
||||||
{
|
}
|
||||||
throw new InvalidOperationException("Context is invalid");
|
finally
|
||||||
}
|
{
|
||||||
|
// 清理:重置上下文提供者
|
||||||
|
PlayerController.ResetContextProvider();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@ -157,4 +157,4 @@ public partial class MyClass
|
|||||||
|
|
||||||
- [Source Generators 概述](./index)
|
- [Source Generators 概述](./index)
|
||||||
- [枚举扩展生成器](./enum-generator)
|
- [枚举扩展生成器](./enum-generator)
|
||||||
- [规则生成器](./rule-generator)
|
- [ContextAware 生成器](./context-aware-generator)
|
||||||
|
|||||||
@ -1,163 +0,0 @@
|
|||||||
# 规则生成器
|
|
||||||
|
|
||||||
> GFramework.SourceGenerators 自动生成规则验证代码
|
|
||||||
|
|
||||||
## 概述
|
|
||||||
|
|
||||||
规则生成器为实现了规则接口的类型自动生成验证方法。这使得规则定义更加简洁,并确保规则的一致性。
|
|
||||||
|
|
||||||
## 基本用法
|
|
||||||
|
|
||||||
### 定义规则
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using GFramework.SourceGenerators.Attributes;
|
|
||||||
|
|
||||||
[RuleFor(typeof(Player))]
|
|
||||||
public class PlayerRule : IRule<Player>
|
|
||||||
{
|
|
||||||
public RuleResult Validate(Player player)
|
|
||||||
{
|
|
||||||
if (player.Health <= 0)
|
|
||||||
{
|
|
||||||
return RuleResult.Invalid("玩家生命值不能为零或负数");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(player.Name))
|
|
||||||
{
|
|
||||||
return RuleResult.Invalid("玩家名称不能为空");
|
|
||||||
}
|
|
||||||
|
|
||||||
return RuleResult.Valid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 使用生成的验证器
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class PlayerValidator
|
|
||||||
{
|
|
||||||
// 自动生成 Validate 方法
|
|
||||||
public void ValidatePlayer(Player player)
|
|
||||||
{
|
|
||||||
var result = PlayerRuleValidator.Validate(player);
|
|
||||||
|
|
||||||
if (!result.IsValid)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"验证失败: {result.ErrorMessage}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 组合规则
|
|
||||||
|
|
||||||
### 多规则组合
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[RuleFor(typeof(Player), RuleCombinationType.And)]
|
|
||||||
public class PlayerHealthRule : IRule<Player>
|
|
||||||
{
|
|
||||||
public RuleResult Validate(Player player)
|
|
||||||
{
|
|
||||||
if (player.Health <= 0)
|
|
||||||
return RuleResult.Invalid("生命值必须大于0");
|
|
||||||
return RuleResult.Valid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[RuleFor(typeof(Player), RuleCombinationType.And)]
|
|
||||||
public class PlayerNameRule : IRule<Player>
|
|
||||||
{
|
|
||||||
public RuleResult Validate(Player player)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(player.Name))
|
|
||||||
return RuleResult.Invalid("名称不能为空");
|
|
||||||
return RuleResult.Valid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 验证所有规则
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public void ValidateAll(Player player)
|
|
||||||
{
|
|
||||||
var results = PlayerRuleValidator.ValidateAll(player);
|
|
||||||
|
|
||||||
foreach (var result in results)
|
|
||||||
{
|
|
||||||
if (!result.IsValid)
|
|
||||||
{
|
|
||||||
Console.WriteLine(result.ErrorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 异步规则
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[RuleFor(typeof(Player), IsAsync = true)]
|
|
||||||
public class AsyncPlayerRule : IAsyncRule<Player>
|
|
||||||
{
|
|
||||||
public async Task<RuleResult> ValidateAsync(Player player)
|
|
||||||
{
|
|
||||||
// 异步验证,如检查服务器
|
|
||||||
var isBanned = await CheckBanStatus(player.Id);
|
|
||||||
|
|
||||||
if (isBanned)
|
|
||||||
{
|
|
||||||
return RuleResult.Invalid("玩家已被封禁");
|
|
||||||
}
|
|
||||||
|
|
||||||
return RuleResult.Valid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 最佳实践
|
|
||||||
|
|
||||||
### 1. 单一职责
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 推荐:每个规则只验证一个方面
|
|
||||||
[RuleFor(typeof(Player))]
|
|
||||||
public class PlayerHealthRule : IRule<Player> { }
|
|
||||||
|
|
||||||
[RuleFor(typeof(Player))]
|
|
||||||
public class PlayerNameRule : IRule<Player> { }
|
|
||||||
|
|
||||||
// 避免:在一个规则中验证多个方面
|
|
||||||
[RuleFor(typeof(Player))]
|
|
||||||
public class PlayerMegaRule : IRule<Player>
|
|
||||||
{
|
|
||||||
public RuleResult Validate(Player player)
|
|
||||||
{
|
|
||||||
// 验证健康、名称、等级...
|
|
||||||
// 不要这样设计
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 清晰的错误信息
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public RuleResult Validate(Player player)
|
|
||||||
{
|
|
||||||
// 推荐:具体的错误信息
|
|
||||||
return RuleResult.Invalid($"玩家 {player.Name} 的生命值 {player.Health} 不能小于 1");
|
|
||||||
|
|
||||||
// 避免:模糊的错误信息
|
|
||||||
return RuleResult.Invalid("无效的玩家");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**相关文档**:
|
|
||||||
|
|
||||||
- [Source Generators 概述](./index)
|
|
||||||
- [日志生成器](./logging-generator)
|
|
||||||
- [枚举扩展生成器](./enum-generator)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user