如何基于LINQ Select重构通用方法以消除代码重复?
代码重构方案:通用化重复检查逻辑
原代码针对DoctorTechnicianDto和HospitalDepartment实现了完全一致的检查逻辑,仅差异在于从RecordingFile提取关联对象的方式和DTO类型。以下是具体重构思路:
1. 抽象统一标识接口
定义一个带Id属性的接口,让所有需要此类检查的DTO实现该接口,统一获取标识的方式:
public interface IHasId { int Id { get; } } // 让现有DTO实现接口 public class DoctorTechnicianDto : IHasId { /* 原有成员 + 实现Id属性 */ } public class HospitalDepartment : IHasId { /* 原有成员 + 实现Id属性 */ }
2. 抽取通用检查方法
将重复的检查逻辑封装为通用方法,通过委托参数传入RecordingFile到目标对象的映射规则:
private void CheckRecordingFileAssociation(IHasId target, Func<RecordingFile, IHasId> extractor, Exam exam, YourEventType e) { var relatedEntities = exam.RecordingFiles.Select(extractor); // 全部匹配则直接返回 if (relatedEntities.All(entity => entity.Id == target.Id)) { return; } // 部分匹配则提示并返回 if (relatedEntities.Any(entity => entity.Id == target.Id)) { ShowMessage(e); } }
注:YourEventType需替换为e参数的实际类型(如自定义事件参数类)。
3. 简化原调用逻辑
用模式匹配或字典映射替代原有的分支判断,调用通用方法:
方式一:模式匹配(直观易读)
switch (e.Value) { case DoctorTechnicianDto dto: CheckRecordingFileAssociation(dto, rf => rf.Doctor, exam, e); break; case HospitalDepartment dept: CheckRecordingFileAssociation(dept, rf => rf.HospitalDepartment, exam, e); break; // 新增DTO时仅需添加新case }
方式二:字典映射(符合开闭原则)
如果后续会频繁新增DTO类型,可预先定义类型与映射规则的字典,避免修改分支判断:
// 静态字典存储类型与映射规则 private static readonly Dictionary<Type, Func<RecordingFile, IHasId>> _entityExtractors = new() { { typeof(DoctorTechnicianDto), rf => rf.Doctor }, { typeof(HospitalDepartment), rf => rf.HospitalDepartment } }; // 调用逻辑 if (e.Value is IHasId target && _entityExtractors.TryGetValue(target.GetType(), out var extractor)) { CheckRecordingFileAssociation(target, extractor, exam, e); }
重构优势
- 新增DTO类型时,仅需实现
IHasId接口并添加映射规则,无需重复编写检查逻辑; - 核心检查逻辑集中维护,降低后续修改成本;
- 代码结构更简洁,可读性与可维护性提升。
内容的提问来源于stack exchange,提问作者Riccardo Zamuner
相关产品推荐
相关产品推荐

