策略模式核心是定义窄而具体的输入输出边界接口,如IChargeProcessor,避免空接口和泛型堆砌;注册应使用AddTransient配合元数据标记,解析用GetServices而非GetService;DI错误需逐级检查构造函数依赖并显式注册。

策略模式在 C# 里不是靠堆 if-else + 接口硬凑出来的,核心是让策略契约足够窄、足够具体。否则很快会陷入“这个策略要传 IDictionary,那个要 CancellationToken,第三个还得返回 Task<result></result>”的泥潭,最后只能用泛型堆砌或 object 强转,反而更难维护。
策略接口别写成空壳 IStrategy
空接口没有行为约束,后续全靠注释和人肉约定——新加一个策略类时,没人知道它该接受什么输入、返回什么结果、是否异步、要不要重试。一上线就崩。
- 按**输入输出边界**定义接口,比如
IChargeProcessor<trequest tresponse></trequest>,而不是笼统的IPaymentStrategy - 接口方法必须明确:是同步还是异步?参数要不要验证?失败时抛异常还是返回错误码?
- 避免在接口里塞横切逻辑(如日志、缓存、重试),这些该由装饰器或中间件统一处理
.NET 6+ 注册策略集合别手写 Dictionary<string istrategy></string>
手动维护字典看似简单,但一接入多租户、插件热加载或需要生命周期管理(比如 Scoped 策略),立刻出问题:服务没注册、Key 写错没提示、作用域错乱、重复注册。
- 注册用
AddTransient<istrategy concretestrategy>()</istrategy>,配合[StrategyName("alipay")]这类元数据标记,比字符串 Key 更安全 - 解析时别直接
GetService<istrategy>()</istrategy>,要用GetServices<istrategy>()</istrategy>拿全部,再按需筛选 - 如果策略依赖
IServiceScope(比如要访问 Scoped 服务),确保调用方自己创建 scope,别在策略内部 new
报 InvalidOperationException: No service for type 'X' has been registered 怎么快速定位
这个错误不是策略类写错了,而是 DI 配置断在某一层:要么策略本身没注册,要么它依赖的某个服务(比如 IHttpClientFactory 或 IOptions<myconfig></myconfig>)漏注册,或者生命周期不匹配(比如 Transient 策略注入了 Singleton 服务,而该服务又依赖 Scoped 服务)。
- 从报错策略类开始,逐个检查构造函数参数,确认每个类型都在
Program.cs里显式注册过 - 特别注意
IOptions<t></t>、IConfiguration这类“看起来自带”的服务——它们必须显式调用AddOptions<t>()</t> - 用
ServiceProvider.GetService<ienumerable>>()</ienumerable>打印所有已注册策略,看有没有漏掉的实现类
策略最难的从来不是写几个类,而是划清边界:哪些该进策略、哪些该由上下文传入、哪些该交给中间件兜底。一旦把“共享 HttpClient”“读配置”“记录耗时”全塞进策略执行方法里,策略就不再是策略,而是大杂烩。


















