GwWuYou f87c9cf421 style(csharp): 格式化代码样式和优化代码结构
- 统一调整代码注释的缩进格式,保持文档注释的一致性
- 简化对象初始化语法,移除不必要的参数名称指定
- 优化条件语句结构,移除多余的花括号
- 调整方法实现格式,使用表达式主体语法简化代码
- 标准化代码缩进和空格使用,提升代码可读性
- [skip ci]
2026-01-04 22:14:34 +08:00
..

Extensions 包使用说明

概述

Extensions 包提供了一系列扩展方法,简化了框架各个接口的使用。通过扩展方法,可以用更简洁的语法访问框架功能,提高代码可读性和开发效率。

扩展方法类别

1. 获取组件扩展 (CanGetExtensions.cs)

ICanGetModelICanGetSystem ICanGetUtility 提供扩展方法。

CanGetModelExtension

public static T GetModel<T>(this ICanGetModel self) where T : class, IModel

使用示例:

// 在 Controller、Command、Query 中使用
public class PlayerController : IController
{
    public void UpdateUI()
    {
        // 直接通过 this 调用
        var playerModel = this.GetModel<PlayerModel>();
        var inventoryModel = this.GetModel<InventoryModel>();
    }
}

CanGetSystemExtension

public static T GetSystem<T>(this ICanGetSystem self) where T : class, ISystem

使用示例:

public class SaveCommand : AbstractCommand
{
    protected override void OnExecute()
    {
        // 获取系统
        var saveSystem = this.GetSystem<SaveSystem>();
        var networkSystem = this.GetSystem<NetworkSystem>();
        
        saveSystem.SaveGame();
    }
}

CanGetUtilityExtension

public static T GetUtility<T>(this ICanGetUtility self) where T : class, IUtility

使用示例:

public class GameModel : AbstractModel
{
    protected override void OnInit()
    {
        // 获取工具
        var timeUtility = this.GetUtility<TimeUtility>();
        var storageUtility = this.GetUtility<StorageUtility>();
    }
}

2. 发送命令扩展 (CanSendExtensions.cs)

ICanSendCommand 提供扩展方法。

CanSendCommandExtension

// 发送无参命令(通过类型)
public static void SendCommand<T>(this ICanSendCommand self) 
    where T : ICommand, new()

// 发送命令实例
public static void SendCommand<T>(this ICanSendCommand self, T command) 
    where T : ICommand

// 发送带返回值的命令
public static TResult SendCommand<TResult>(this ICanSendCommand self, 
    ICommand<TResult> command)

使用示例:

public class GameController : IController
{
    public void OnStartButtonClicked()
    {
        // 方式1通过类型发送需要无参构造函数
        this.SendCommand<StartGameCommand>();
        
        // 方式2发送命令实例
        this.SendCommand(new LoadLevelCommand(levelId: 1));
        
        // 方式3发送带返回值的命令
        var score = this.SendCommand(new CalculateScoreCommand());
    }
}

3. 发送事件扩展 (CanSendExtensions.cs)

ICanSendEvent 提供扩展方法。

CanSendEventExtension

// 发送无参事件
public static void SendEvent<T>(this ICanSendEvent self) where T : new()

// 发送事件实例
public static void SendEvent<T>(this ICanSendEvent self, T e)

使用示例:

public class PlayerModel : AbstractModel
{
    public void TakeDamage(int damage)
    {
        Health -= damage;
        
        if (Health <= 0)
        {
            // 方式1发送无参事件
            this.SendEvent<PlayerDiedEvent>();
            
            // 方式2发送带数据的事件
            this.SendEvent(new PlayerDiedEvent 
            { 
                Position = Position,
                Cause = "Damage" 
            });
        }
    }
}

4. 发送查询扩展 (CanSendExtensions.cs)

ICanSendQuery 提供扩展方法。

CanSendQueryExtension

public static TResult SendQuery<TResult>(this ICanSendQuery self, 
    IQuery<TResult> query)

使用示例:

public class InventoryController : IController
{
    public void ShowInventory()
    {
        // 发送查询获取数据
        var items = this.SendQuery(new GetInventoryItemsQuery());
        var gold = this.SendQuery(new GetPlayerGoldQuery());
        
        UpdateInventoryUI(items, gold);
    }
}

5. 注册事件扩展 (CanRegisterEventExtensions.cs)

ICanRegisterEvent 提供扩展方法。

CanRegisterEventExtensions

// 注册事件
public static IUnRegister RegisterEvent<T>(this ICanRegisterEvent self, 
    Action<T> onEvent)

// 注销事件
public static void UnRegisterEvent<T>(this ICanRegisterEvent self, 
    Action<T> onEvent)

使用示例:

public class GameController : Node, IController
{
    private IUnRegisterList _unregisterList = new UnRegisterList();
    
    public override void _Ready()
    {
        // 注册事件监听
        this.RegisterEvent<GameStartedEvent>(OnGameStarted)
            .AddToUnregisterList(_unregisterList);
            
        this.RegisterEvent<PlayerLevelUpEvent>(OnPlayerLevelUp)
            .AddToUnregisterList(_unregisterList);
    }
    
    private void OnGameStarted(GameStartedEvent e) { }
    private void OnPlayerLevelUp(PlayerLevelUpEvent e) { }
}

6. OrEvent 扩展 (OrEventExtensions.cs)

IEasyEvent 提供事件组合功能。

OrEventExtensions

public static OrEvent Or(this IEasyEvent self, IEasyEvent e)

使用示例:

// 组合多个事件:当任意一个触发时执行
var onAnyInput = onKeyPressed.Or(onMouseClicked).Or(onTouchDetected);

onAnyInput.Register(() => 
{
    GD.Print("Any input detected!");
});

// 链式组合
var onAnyDamage = onPhysicalDamage
    .Or(onMagicDamage)
    .Or(onPoisonDamage);

7. UnRegister 扩展 (UnRegisterExtension.cs)

IUnRegister 提供 Godot 生命周期绑定。

UnRegisterExtension

public static IUnRegister UnRegisterWhenNodeExitTree(this IUnRegister unRegister, 
    Node node)

使用示例:

#if GODOT
public class PlayerController : Node, IController
{
    public override void _Ready()
    {
        // 当节点退出场景树时自动注销
        this.RegisterEvent<GameEvent>(OnGameEvent)
            .UnRegisterWhenNodeExitTree(this);
            
        this.GetModel<PlayerModel>()
            .Health
            .Register(OnHealthChanged)
            .UnRegisterWhenNodeExitTree(this);
    }
    
    // 不需要手动在 _ExitTree 中注销
}
#endif

8. UnRegisterList 扩展 (UnRegisterListExtension.cs)

IUnRegisterIUnRegisterList 提供批量管理功能。

UnRegisterListExtension

// 添加到注销列表
public static void AddToUnregisterList(this IUnRegister self, 
    IUnRegisterList unRegisterList)

// 批量注销
public static void UnRegisterAll(this IUnRegisterList self)

使用示例:

public class ComplexController : Node, IController
{
    private IUnRegisterList _unregisterList = new UnRegisterList();
    
    public override void _Ready()
    {
        // 所有注册都添加到列表中
        this.RegisterEvent<Event1>(OnEvent1)
            .AddToUnregisterList(_unregisterList);
            
        this.RegisterEvent<Event2>(OnEvent2)
            .AddToUnregisterList(_unregisterList);
            
        this.GetModel<Model1>().Property1.Register(OnProperty1Changed)
            .AddToUnregisterList(_unregisterList);
            
        this.GetModel<Model2>().Property2.Register(OnProperty2Changed)
            .AddToUnregisterList(_unregisterList);
    }
    
    public override void _ExitTree()
    {
        // 一次性注销所有
        _unregisterList.UnRegisterAll();
    }
}

完整使用示例

Controller 示例

public partial class GameplayController : Node, IController
{
    private IUnRegisterList _unregisterList = new UnRegisterList();
    
    public IArchitecture GetArchitecture() => GameArchitecture.Interface;
    
    public override void _Ready()
    {
        // 使用扩展方法获取 Model
        var playerModel = this.GetModel<PlayerModel>();
        var gameModel = this.GetModel<GameModel>();
        
        // 使用扩展方法注册事件
        this.RegisterEvent<GameStartedEvent>(OnGameStarted)
            .AddToUnregisterList(_unregisterList);
        
        // 监听可绑定属性
        playerModel.Health.Register(OnHealthChanged)
            .AddToUnregisterList(_unregisterList);
        
        // 或者使用 Godot 特定的自动注销
        gameModel.Score.Register(OnScoreChanged)
            .UnRegisterWhenNodeExitTree(this);
    }
    
    public override void _Process(double delta)
    {
        if (Input.IsActionJustPressed("attack"))
        {
            // 使用扩展方法发送命令
            this.SendCommand(new AttackCommand(targetId: 1));
        }
        
        if (Input.IsActionJustPressed("use_item"))
        {
            // 使用扩展方法发送查询
            var hasPotion = this.SendQuery(new HasItemQuery("health_potion"));
            if (hasPotion)
            {
                this.SendCommand<UseHealthPotionCommand>();
            }
        }
    }
    
    private void OnGameStarted(GameStartedEvent e)
    {
        GD.Print("Game started!");
    }
    
    private void OnHealthChanged(int health)
    {
        UpdateHealthBar(health);
    }
    
    private void OnScoreChanged(int score)
    {
        UpdateScoreDisplay(score);
    }
    
    public override void _ExitTree()
    {
        _unregisterList.UnRegisterAll();
    }
}

Command 示例

public class ComplexGameCommand : AbstractCommand
{
    protected override void OnExecute()
    {
        // 获取多个组件
        var playerModel = this.GetModel<PlayerModel>();
        var gameSystem = this.GetSystem<GameSystem>();
        var timeUtility = this.GetUtility<TimeUtility>();
        
        // 执行业务逻辑
        var currentTime = timeUtility.GetCurrentTime();
        gameSystem.ProcessGameLogic(playerModel, currentTime);
        
        // 发送事件通知
        this.SendEvent(new GameStateChangedEvent());
        
        // 可以发送其他命令(谨慎使用)
        this.SendCommand<SaveGameCommand>();
    }
}

System 示例

public class AchievementSystem : AbstractSystem
{
    protected override void OnInit()
    {
        // 注册事件监听
        this.RegisterEvent<EnemyKilledEvent>(OnEnemyKilled);
        this.RegisterEvent<LevelCompletedEvent>(OnLevelCompleted);
    }
    
    private void OnEnemyKilled(EnemyKilledEvent e)
    {
        // 获取模型
        var playerModel = this.GetModel<PlayerModel>();
        playerModel.EnemyKillCount++;
        
        // 检查成就
        if (playerModel.EnemyKillCount >= 100)
        {
            // 发送成就解锁事件
            this.SendEvent(new AchievementUnlockedEvent 
            { 
                AchievementId = "kill_100_enemies" 
            });
        }
    }
    
    private void OnLevelCompleted(LevelCompletedEvent e)
    {
        // 发送查询
        var completionTime = this.SendQuery(new GetLevelTimeQuery(e.LevelId));
        
        if (completionTime < 60)
        {
            this.SendEvent(new AchievementUnlockedEvent 
            { 
                AchievementId = "speed_runner" 
            });
        }
    }
}

扩展方法的优势

  1. 简洁的语法:不需要显式调用 GetArchitecture()
  2. 类型安全:编译时检查类型
  3. 可读性高:代码意图更清晰
  4. 智能提示IDE 可以提供完整的自动补全
  5. 链式调用:支持流式编程风格

注意事项

  1. 确保引用命名空间

    using GFramework.framework.extensions;
    
  2. 理解扩展方法本质

    • 扩展方法是静态方法的语法糖
    • 不会改变原始类型的结构
    • 仅在编译时解析
  3. Godot 特定功能

    • UnRegisterWhenNodeExitTree 仅在 Godot 环境下可用
    • 使用 #if GODOT 编译指令控制
  4. 性能考虑

    • 扩展方法本身无性能开销
    • 实际调用的是底层方法

相关包