如何避免在集合所用接口的方法中使用object类型参数?
避免object类型,提升类型安全并消除装箱/拆箱的解决方案
当前代码通过object存储检查结果值,存在类型转换风险、编译时无法校验类型,以及值类型装箱/拆箱的性能损耗问题。要在保持集合存储能力的前提下解决这些问题,泛型接口+访问者模式是非常合适的方案,既能满足统一集合存储,又能完全消除object的使用。
重构后的代码实现
1. 定义访问者与验证器接口
先通过访问者模式的接口,实现不同类型结果的类型安全处理:
// 非泛型访问者基接口,用于集合中统一调用 public interface IResultVisitor { void Visit(StringResult result); void Visit(DoubleResult result); void Visit(EnumResult<MyEnum> result); // 新增类型时扩展对应的Visit方法即可 } // 泛型验证器接口,绑定具体类型的验证逻辑 public interface IResultValidator<T> { bool Validate(T value); }
2. 定义结果接口与实现类
用非泛型接口作为集合存储的统一类型,泛型接口实现强类型值存储:
// 非泛型基接口,用于存入集合 public interface IServiceCheckResult { void Accept(IResultVisitor visitor); } // 泛型结果接口,强类型管理值与验证器 public interface IServiceCheckResult<T> : IServiceCheckResult { T Value { get; set; } IResultValidator<T> Validator { get; } } // 字符串结果实现 public class StringResult : IServiceCheckResult<string> { public string Value { get; set; } = string.Empty; public IResultValidator<string> Validator { get; } public StringResult(IResultValidator<string> validator) { Validator = validator; } public void Accept(IResultVisitor visitor) { visitor.Visit(this); } } // 双精度浮点数结果实现 public class DoubleResult : IServiceCheckResult<double> { public double Value { get; set; } public IResultValidator<double> Validator { get; } public DoubleResult(IResultValidator<double> validator) { Validator = validator; } public void Accept(IResultVisitor visitor) { visitor.Visit(this); } } // 泛型枚举结果实现 public class EnumResult<TEnum> : IServiceCheckResult<TEnum> where TEnum : Enum { public TEnum Value { get; set; } = default!; public IResultValidator<TEnum> Validator { get; } public EnumResult(IResultValidator<TEnum> validator) { Validator = validator; } public void Accept(IResultVisitor visitor) { visitor.Visit(this); } }
3. 具体验证器实现
每个验证器绑定对应类型,无需强制转换:
public class StringEmptyValidator : IResultValidator<string> { public bool Validate(string value) { return string.IsNullOrEmpty(value); } } public class DoublePositiveValidator : IResultValidator<double> { public bool Validate(double value) { return value > 0; } } public class EnumValidValidator : IResultValidator<MyEnum> { public bool Validate(MyEnum value) { return Enum.IsDefined(typeof(MyEnum), value); } }
4. 验证执行的访问者
实现访问者来统一处理所有类型的验证逻辑:
public class ValidationVisitor : IResultVisitor { // 存储所有验证结果 public List<bool> ValidationResults { get; } = new(); public void Visit(StringResult result) { ValidationResults.Add(result.Validator.Validate(result.Value)); } public void Visit(DoubleResult result) { ValidationResults.Add(result.Validator.Validate(result.Value)); } public void Visit(EnumResult<MyEnum> result) { ValidationResults.Add(result.Validator.Validate(result.Value)); } }
5. 优化后的ServiceCheck与使用示例
可以给ServiceCheck添加泛型方法,避免设置值时的强制转换:
public class ServiceCheck { private readonly List<IServiceCheckResult> _results = new(); public IReadOnlyList<IServiceCheckResult> Results => _results.AsReadOnly(); public void AddResult<T>(IServiceCheckResult<T> result) { _results.Add(result); } public IServiceCheckResult<T>? GetResult<T>(int index) { return _results[index] as IServiceCheckResult<T>; } } // 使用示例 var serviceCheck = new ServiceCheck(); serviceCheck.AddResult(new DoubleResult(new DoublePositiveValidator())); serviceCheck.AddResult(new StringResult(new StringEmptyValidator())); serviceCheck.AddResult(new EnumResult<MyEnum>(new EnumValidValidator())); // 强类型设置值,无装箱/拆箱,编译时校验类型 serviceCheck.GetResult<double>(0)!.Value = 1.0; serviceCheck.GetResult<string>(1)!.Value = "This is a test"; serviceCheck.GetResult<MyEnum>(2)!.Value = MyEnum.None; // 执行验证 var validationVisitor = new ValidationVisitor(); foreach (var result in serviceCheck.Results) { result.Accept(validationVisitor); } // 输出验证结果 foreach (var isValid in validationVisitor.ValidationResults) { Console.WriteLine(isValid); }
方案优势
- 完全类型安全:所有值都是强类型存储,编译时就能发现类型错误,避免运行时强制转换异常
- 消除装箱/拆箱:值类型(如double、枚举)直接存储,没有
object带来的装箱损耗 - 扩展性良好:新增结果类型时,只需扩展访问者的Visit方法、新增对应结果类和验证器,符合开闭原则
- 职责清晰:结果类负责存值,验证器负责校验逻辑,访问者负责统一处理,代码结构更清晰
内容的提问来源于stack exchange,提问作者zman
相关产品推荐
相关产品推荐

