You need to enable JavaScript to run this app. C# GeneralService类职责梳理及行业最佳实践重构方案咨询
优惠活动
大模型
产品
解决方案
定价
更多

C# GeneralService类职责梳理及行业最佳实践重构方案咨询

现有类的职责边界问题

当前GeneralService实际同时承担了4类无关联逻辑,完全违反单一职责原则:

  • 作为事件订阅者,在构造函数阶段注册全局异常事件总线的监听,实现IDisposable用于触发事件反订阅
  • 作为通用执行封装器,接收传入的任意委托,统一完成执行日志打印、耗时统计、执行耗时落库、执行过程异常捕获与日志记录
  • 作为全局异常处理器,接收事件总线推送的异常,完成异常落库、异常处理结果日志打印
  • 无意义的依赖中转:同时注入IServiceProvider、LoggingService、DataService,但依赖使用完全混乱

核心边界模糊的根源:类名GeneralService本身是反模式,没有明确的功能指向,天然会成为后续维护时各种无关逻辑的“垃圾桶”

除了职责拆分问题,现有代码还存在明确的硬伤:

  • 依赖使用混乱:构造函数已经注入了LoggingService,但Execute方法又从IServiceProvider重新拉取一次LoggingService,HandleException方法甚至直接new了一个全新的LoggingService实例,完全没有复用已注入的依赖
  • 大量拼写错误:_logginService拼写缺字符、serviceProvider.getService大小写不规范、StopWatch类名拼写错误、watch.stop()方法名大小写错误、ElapsedMillieseconds多写字符、日志文本存在乱码"Ëxception"
  • 引入了不必要的服务定位器反模式:类内注入IServiceProvider用于按需拉取服务,直接破坏了依赖的显式声明特性,既不利于单元测试,也会让类的真实依赖关系隐藏起来
重构落地方案

按照行业通用的单一职责、显式依赖原则,把现有类拆分为两个完全独立的服务:

1. 通用执行封装服务

仅保留Action执行封装的相关逻辑,移除所有事件订阅、反订阅相关代码,命名为ActionExecutionService,职责边界清晰:

public class ActionExecutionService
{
    private readonly LoggingService _loggingService;
    private readonly DataService _dataService;

    public ActionExecutionService(LoggingService loggingService, DataService dataService)
    {
        _loggingService = loggingService;
        _dataService = dataService;
    }

    public void Execute(Action action)
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        _loggingService.LogInformation("Start Executing action");

        try
        {
            action();
        }
        catch (Exception exception)
        {
            _loggingService.LogException(exception);
            return;
        }

        stopwatch.Stop();
        _dataService.CreateLog($"{nameof(ActionExecutionService)} - {nameof(Execute)}: {stopwatch.ElapsedMilliseconds}ms");
    }
}

这个类的优化点:

  • 彻底移除IServiceProvider依赖,所有需要的服务通过构造函数显式注入
  • 全程复用注入的LoggingService、DataService实例,不存在重复拉取、手动new的情况
  • 修正所有拼写、大小写错误

2. 全局异常事件处理服务

仅保留事件订阅、全局异常处理的相关逻辑,命名为GlobalExceptionEventHandler,职责为接收事件总线推送的全局异常,完成异常的持久化存储与处理日志记录:

public class GlobalExceptionEventHandler : IDisposable
{
    private readonly LoggingService _loggingService;
    private readonly DataService _dataService;
    private readonly EventBusProvider _eventBusProvider;

    public GlobalExceptionEventHandler(LoggingService loggingService, DataService dataService, EventBusProvider eventBusProvider)
    {
        _loggingService = loggingService;
        _dataService = dataService;
        _eventBusProvider = eventBusProvider;
        
        _eventBusProvider.RegisterForNotification(this, EventTypes.Exception, HandleException);
    }

    private void HandleException(Exception exception)
    {
        _dataService.CreateLog(exception);
        _loggingService.LogInformation("Exception was logged to storage");
    }

    public void Dispose()
    {
        _eventBusProvider.UnRegisterForNotification(this);
    }
}

这个类的优化点:

  • 直接注入EventBusProvider,不再通过IServiceProvider按需拉取
  • 复用已注入的服务实例,移除手动newLoggingService的逻辑
  • 修正日志乱码问题

通用后续优化规则

  • 彻底废弃GeneralService这类无明确职责指向的命名,所有服务类的命名必须直接对应其核心功能,避免后续维护时无关逻辑随意塞入
  • 全面禁用服务定位器反模式:所有类的依赖全部通过构造函数显式声明,不通过IServiceProvider在类内部按需拉取服务,保证依赖关系透明、可测试
  • 统一依赖生命周期管理:LoggingService、DataService这类基础服务通常注册为单例,注入一次即可全程复用,不允许出现重复拉取、手动创建实例的情况

内容的提问来源于stack exchange,提问作者user10361591

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.29 09:06:07