mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +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)
|
||||
- [日志生成器](./logging-generator)
|
||||
- [规则生成器](./rule-generator)
|
||||
- [ContextAware 生成器](./context-aware-generator)
|
||||
|
||||
@ -184,8 +184,8 @@ public partial class WarningOnlyLogger
|
||||
### 基础使用
|
||||
|
||||
```csharp
|
||||
using GFramework.SourceGenerators.Attributes;
|
||||
using GFramework.Core.Abstractions;
|
||||
using GFramework.SourceGenerators.Abstractions.rule;
|
||||
using GFramework.Core.Abstractions.controller;
|
||||
|
||||
[ContextAware]
|
||||
public partial class PlayerController : IController
|
||||
@ -195,7 +195,7 @@ public partial class PlayerController : IController
|
||||
// Context 属性自动生成,提供架构上下文访问
|
||||
var playerModel = Context.GetModel<PlayerModel>();
|
||||
var combatSystem = Context.GetSystem<CombatSystem>();
|
||||
|
||||
|
||||
Context.SendEvent(new PlayerInitializedEvent());
|
||||
}
|
||||
}
|
||||
@ -207,57 +207,84 @@ public partial class PlayerController : IController
|
||||
|
||||
```csharp
|
||||
// <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;
|
||||
|
||||
public IContextAware.Context Context => _context ??= new LazyContext(this);
|
||||
|
||||
public void SetContext(IContextAware.Context context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IContextAware.Context GetContext()
|
||||
get
|
||||
{
|
||||
if (_context == null)
|
||||
{
|
||||
_contextProvider ??= new global::GFramework.Core.architecture.GameContextProvider();
|
||||
_context = _contextProvider.GetContext();
|
||||
}
|
||||
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 延迟初始化
|
||||
|
||||
```csharp
|
||||
[ContextAware(useLazy = true)]
|
||||
public partial class LazyContextExample
|
||||
{
|
||||
public void AccessContext()
|
||||
/// <summary>
|
||||
/// 配置上下文提供者(用于测试或多架构场景)
|
||||
/// </summary>
|
||||
public static void SetContextProvider(global::GFramework.Core.Abstractions.architecture.IArchitectureContextProvider provider)
|
||||
{
|
||||
// Context 会延迟初始化,直到第一次访问
|
||||
var model = Context.GetModel<SomeModel>();
|
||||
_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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 上下文验证
|
||||
### 测试场景配置
|
||||
|
||||
在单元测试中,可以配置自定义的上下文提供者:
|
||||
|
||||
```csharp
|
||||
[ContextAware(validateContext = true)]
|
||||
public partial class ValidatedContextExample
|
||||
[Test]
|
||||
public async Task TestPlayerController()
|
||||
{
|
||||
public void AccessContext()
|
||||
var testArchitecture = new TestArchitecture();
|
||||
await testArchitecture.InitAsync();
|
||||
|
||||
// 配置测试上下文提供者
|
||||
PlayerController.SetContextProvider(new TestContextProvider(testArchitecture));
|
||||
|
||||
try
|
||||
{
|
||||
// 每次访问都会验证上下文的有效性
|
||||
var model = Context.GetModel<SomeModel>();
|
||||
if (Context.IsInvalid)
|
||||
{
|
||||
throw new InvalidOperationException("Context is invalid");
|
||||
}
|
||||
var controller = new PlayerController();
|
||||
controller.Initialize();
|
||||
// 测试逻辑...
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 清理:重置上下文提供者
|
||||
PlayerController.ResetContextProvider();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -157,4 +157,4 @@ public partial class MyClass
|
||||
|
||||
- [Source Generators 概述](./index)
|
||||
- [枚举扩展生成器](./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