含互斥成员的构造函数及CellCheck类互斥属性技术咨询
处理含互斥属性类的构造函数与属性方案
嘿,这个问题在业务代码里真的很常见——要确保类的属性组合符合业务规则,避免无效配置被误用。我给你几个从易到优的实现方案,兼顾代码安全性和可读性:
方案一:私有构造函数 + 静态工厂方法(推荐)
这种方式能在编译阶段就阻止无效的属性组合,用户只能通过预定义的合法方式创建实例,完全避免误用。
实现代码如下:
enum CellType : byte { Date, Teams, Value, Text } class CellCheck { // 私有构造函数,禁止外部直接实例化 private CellCheck(CellType cellType) { CellType = cellType; } public CellType CellType { get; } // 设为只读,避免后续修改导致属性失效 public float? MinValue { get; } public float? MaxValue { get; } public bool TextCaseSensitive { get; } public string Text { get; } // 针对每种CellType的静态工厂方法 public static CellCheck CreateDateCellCheck() { return new CellCheck(CellType.Date); } public static CellCheck CreateTeamsCellCheck() { return new CellCheck(CellType.Teams); } public static CellCheck CreateValueCellCheck(float? minValue = null, float? maxValue = null) { // 这里还可以加参数验证,比如minValue <= maxValue if (minValue.HasValue && maxValue.HasValue && minValue > maxValue) { throw new ArgumentException("MinValue cannot be greater than MaxValue"); } return new CellCheck(CellType.Value) { MinValue = minValue, MaxValue = maxValue }; } public static CellCheck CreateTextCellCheck(string text, bool caseSensitive = false) { if (string.IsNullOrEmpty(text)) { throw new ArgumentNullException(nameof(text)); } return new CellCheck(CellType.Text) { Text = text, TextCaseSensitive = caseSensitive }; } }
使用时直接调用对应工厂方法:
var valueCell = CellCheck.CreateValueCellCheck(minValue: 0, maxValue: 100); var textCell = CellCheck.CreateTextCellCheck("Hello World", caseSensitive: true);
优点:编译时安全,代码意图清晰,不会出现无效属性组合。
方案二:基于继承的多态设计(更优雅的类型安全方案)
如果不同CellType的逻辑差异较大,把它们拆分成不同的子类会更清晰,每个子类只包含自己需要的属性:
enum CellType : byte { Date, Teams, Value, Text } // 基类只定义公共属性 abstract class CellCheck { public abstract CellType CellType { get; } } class DateCellCheck : CellCheck { public override CellType CellType => CellType.Date; } class TeamsCellCheck : CellCheck { public override CellType CellType => CellType.Teams; } class ValueCellCheck : CellCheck { public override CellType CellType => CellType.Value; public float? MinValue { get; set; } public float? MaxValue { get; set; } // 可以在构造函数里加参数验证 public ValueCellCheck(float? minValue = null, float? maxValue = null) { if (minValue.HasValue && maxValue.HasValue && minValue > maxValue) { throw new ArgumentException("MinValue cannot exceed MaxValue"); } MinValue = minValue; MaxValue = maxValue; } } class TextCellCheck : CellCheck { public override CellType CellType => CellType.Text; public bool CaseSensitive { get; set; } public string Text { get; set; } public TextCellCheck(string text, bool caseSensitive = false) { Text = text ?? throw new ArgumentNullException(nameof(text)); CaseSensitive = caseSensitive; } }
这种方案的优势是类型本身就代表了合法的配置,完全不存在无效属性的问题,后续扩展新的CellType也很方便(新增子类即可)。
方案三:运行时验证(兼容已有代码的兜底方案)
如果因为历史原因不能修改类的整体结构,只能在构造函数或属性setter里加验证逻辑,确保属性组合合法:
enum CellType : byte { Date, Teams, Value, Text } class CellCheck { private CellType _cellType; public CellType CellType { get => _cellType; set { _cellType = value; // 切换类型时清空无效属性 ResetInvalidProperties(value); } } public float? MinValue { get; set; } public float? MaxValue { get; set; } public bool TextCaseSensitive { get; set; } public string Text { get; set; } // 构造函数验证 public CellCheck(CellType cellType) { CellType = cellType; ResetInvalidProperties(cellType); } // 额外的验证方法,用于外部设置属性时检查 public void Validate() { switch (CellType) { case CellType.Date: case CellType.Teams: if (MinValue.HasValue || MaxValue.HasValue || TextCaseSensitive || !string.IsNullOrEmpty(Text)) { throw new InvalidOperationException($"CellType {CellType} cannot have MinValue, MaxValue, TextCaseSensitive or Text set"); } break; case CellType.Value: if (!string.IsNullOrEmpty(Text) || TextCaseSensitive) { throw new InvalidOperationException($"CellType {CellType} cannot have Text or TextCaseSensitive set"); } if (MinValue.HasValue && MaxValue.HasValue && MinValue > MaxValue) { throw new InvalidOperationException("MinValue cannot be greater than MaxValue"); } break; case CellType.Text: if (MinValue.HasValue || MaxValue.HasValue) { throw new InvalidOperationException($"CellType {CellType} cannot have MinValue or MaxValue set"); } if (string.IsNullOrEmpty(Text)) { throw new InvalidOperationException($"CellType {CellType} requires Text to be set"); } break; } } private void ResetInvalidProperties(CellType cellType) { switch (cellType) { case CellType.Date: case CellType.Teams: MinValue = null; MaxValue = null; TextCaseSensitive = false; Text = null; break; case CellType.Value: TextCaseSensitive = false; Text = null; break; case CellType.Text: MinValue = null; MaxValue = null; break; } } }
使用时需要记得调用Validate()方法来确保配置合法,或者在属性setter里实时验证。这种方案的缺点是错误只能在运行时发现,但适合无法重构的老项目。
总结建议
- 优先选静态工厂方法或继承多态,它们能在编译时保证属性组合的合法性,代码更健壮;
- 如果是老项目无法重构,再用运行时验证作为兜底;
- 尽量把
CellType设为只读,避免后续修改导致属性失效(除非业务允许动态切换类型)。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

