C# 10 如何避免类型切换为不同IResponse子类型匹配对应评估器
解决方案
针对你的需求,推荐优先使用类型映射+非泛型评估器包装的实现方案,完全符合开闭原则,不需要每次新增答复类型修改原有聚合器代码,C# 10 原生支持,改动成本极低。
实现步骤
1. 新增非泛型评估器统一入口
定义非泛型基础评估器接口,用来抹平不同泛型评估器的类型差异:
public interface IResponseEvaluator { decimal Evaluate(object response); bool CanEvaluate(Type responseType); }
让原有泛型IResponseEvaluator继承该接口,用显式接口实现封装内部逻辑,不对外暴露非泛型方法:
interface IResponseEvaluator<TQuestion, TResponse> : IResponseEvaluator where TQuestion : Question where TResponse : IResponse<TQuestion> { decimal Evaluate(TResponse response); // 显式实现非泛型接口,仅内部调用 decimal IResponseEvaluator.Evaluate(object response) => Evaluate((TResponse)response); bool IResponseEvaluator.CanEvaluate(Type responseType) => typeof(TResponse).IsAssignableFrom(responseType); }
2. 重构EvaluationAggregator
删除原有零散的评估器属性,改为统一存储所有注册的评估器,动态匹配对应类型:
class EvaluationAggregator { private readonly List<IResponseEvaluator> _registeredEvaluators = new(); // 供构建器调用的评估器注册方法 internal void RegisterEvaluator(IResponseEvaluator evaluator) => _registeredEvaluators.Add(evaluator); public decimal EvaluateAll(IEnumerable<IResponse<Question>> responses) { decimal totalScore = 0; foreach (var response in responses) { var evaluator = _registeredEvaluators.FirstOrDefault(e => e.CanEvaluate(response.GetType())); if (evaluator == null) { // 可根据业务需求自定义未匹配到评估器的逻辑 throw new NotSupportedException($"未找到响应类型 {response.GetType().Name} 对应的评估器"); } totalScore += evaluator.Evaluate(response); } return totalScore; } }
3. 优化构建器实现
新增通用的评估器注册方法,兼容原有调用习惯的同时支持扩展:
class EvaluationAggregatorBuilder { private readonly EvaluationAggregator _aggregator = new(); // 通用注册方法,新增类型时直接调用即可 public EvaluationAggregatorBuilder AddEvaluator<TQuestion, TResponse>(IResponseEvaluator<TQuestion, TResponse> evaluator) where TQuestion : Question where TResponse : IResponse<TQuestion> { _aggregator.RegisterEvaluator(evaluator); return this; } // 保留原有强类型注册方法,兼容旧代码 public EvaluationAggregatorBuilder UseChoiceEvaluator(DefaultMultipleChoiceResponseEvaluator evaluator) => AddEvaluator<MultipleChoiceQuestion, MultipleChoiceResponse>(evaluator); public EvaluationAggregatorBuilder UseTextEvaluator(DefaultTextResponseEvaluator evaluator) => AddEvaluator<TextQuestion, TextResponse>(evaluator); public EvaluationAggregator Build() => _aggregator; }
扩展规则
后续新增答复类型时,仅需要做3件事,不需要修改任何原有逻辑:
- 新增对应
IResponse<新Question类型>的实现类 - 新增对应
IResponseEvaluator<新Question类型, 新Response类型>的实现类 - 在构建器调用
AddEvaluator方法注册新的评估器即可
轻量替代方案(仅推荐小体量项目使用)
如果追求代码极简,可直接用dynamic动态派发实现,不需要修改原有评估器接口,仅需修改聚合器和构建器:
class EvaluationAggregator { private readonly Dictionary<Type, dynamic> _evaluatorMap = new(); internal void RegisterEvaluator(Type responseType, dynamic evaluator) => _evaluatorMap[responseType] = evaluator; public decimal EvaluateAll(IEnumerable<IResponse<Question>> responses) { decimal totalScore = 0; foreach (var response in responses) { if (!_evaluatorMap.TryGetValue(response.GetType(), out var evaluator)) { throw new NotSupportedException($"未找到响应类型 {response.GetType().Name} 对应的评估器"); } totalScore += evaluator.Evaluate((dynamic)response); } return totalScore; } }
该方案牺牲了部分类型安全性和性能,代码量减少30%左右,适合响应类型数量少于10个的小型项目。
内容的提问来源于stack exchange,提问作者Amal K
相关产品推荐
相关产品推荐

