.NET 6 Web API中如何避免多类继承的属性重复?
解决C#单继承限制下的属性重复问题
针对你的场景,核心问题是C#不支持类多继承导致的重复属性定义,这里提供几种实用的解决方案:
方案1:组合模式(推荐)
把重复的MapDepartment、MapAnother1等属性提取到独立的类中,然后在两个参数类里通过组合复用这个类的实例,既避免重复代码,又保持类结构的灵活性。
实现代码:
// 提取所有重复属性到单独的类中 public class ProgramFilterAttributes { public bool? MapDepartment { get; set; } public bool? MapAnother1 { get; set; } // 其他需要复用的属性 } // 非分页参数类:继承QueryStringParameters + 组合复用过滤属性 public class ProgramParameters : QueryStringParameters { public ProgramFilterAttributes Filters { get; set; } = new(); // 如果需要保持原有API的属性访问方式(不希望通过.Filters跳转),可以包装属性: public bool? MapDepartment { get => Filters.MapDepartment; set => Filters.MapDepartment = value; } public bool? MapAnother1 { get => Filters.MapAnother1; set => Filters.MapAnother1 = value; } } // 分页参数类:继承QueryStringParametersPaginated + 组合复用过滤属性 public class ProgramParametersPaginated : QueryStringParametersPaginated { public ProgramFilterAttributes Filters { get; set; } = new(); // 同样包装属性以保持原有访问方式 public bool? MapDepartment { get => Filters.MapDepartment; set => Filters.MapDepartment = value; } public bool? MapAnother1 { get => Filters.MapAnother1; set => Filters.MapAnother1 = value; } }
优点:
- 完全消除重复代码,所有过滤属性只维护一次
- 符合SOLID原则中的单一职责,过滤逻辑和分页逻辑分离
- 灵活度高,后续新增过滤属性只需修改
ProgramFilterAttributes
方案2:调整继承层级 + 接口规范分页属性
如果希望保留类继承的结构,可以把重复属性放到一个基础参数类中,再通过接口来定义分页属性的规范,避免多继承冲突。
实现代码:
// 定义分页属性的接口 public interface IPaginatedParams { int PageNumber { get; set; } int PageSize { get; set; } // 其他分页相关属性 } // 基础Program参数类:继承QueryStringParameters + 包含所有重复属性 public class ProgramBaseParams : QueryStringParameters { public bool? MapDepartment { get; set; } public bool? MapAnother1 { get; set; } // 其他复用属性 } // 非分页参数直接使用基础类 public class ProgramParameters : ProgramBaseParams { } // 分页参数类:继承基础类 + 实现分页接口 public class ProgramParametersPaginated : ProgramBaseParams, IPaginatedParams { public int PageNumber { get; set; } = 1; // 设置默认值 public int PageSize { get; set; } = 10; }
优点:
- 继承层级清晰,非分页和分页参数类共享同一套过滤属性
- 分页属性通过接口统一规范,便于后续其他参数类复用分页逻辑
方案3:使用接口默认实现(C# 8.0+)
如果项目使用C# 8.0及以上版本,可以利用接口的默认实现来复用属性逻辑,但注意接口无法直接存储状态,需要结合内部存储容器,适合简单场景:
实现代码:
public interface IProgramFilterParams { private Dictionary<string, object?> _filterValues { get; } = new(); bool? MapDepartment { get => _filterValues.TryGetValue(nameof(MapDepartment), out var value) ? (bool?)value : null; set => _filterValues[nameof(MapDepartment)] = value; } bool? MapAnother1 { get => _filterValues.TryGetValue(nameof(MapAnother1), out var value) ? (bool?)value : null; set => _filterValues[nameof(MapAnother1)] = value; } } // 非分页参数类 public class ProgramParameters : QueryStringParameters, IProgramFilterParams { } // 分页参数类 public class ProgramParametersPaginated : QueryStringParametersPaginated, IProgramFilterParams { }
注意:
- 接口的私有成员是C# 8.0新增特性,需要确保项目语言版本支持
- 这种方式的状态存储不够直观,复杂场景下不如组合模式易维护
内容的提问来源于stack exchange,提问作者RoLYroLLs
相关产品推荐
相关产品推荐

