C# 如何以泛型类型安全的方式验证层次结构中的类?
我一开始就被一项看起来很简单的任务困住了。我有一个类层次结构,每个类都可以定义自己的验证规则。定义验证规则应该尽可能简单。以下是我们所需要的:C# 如何以泛型类型安全的方式验证层次结构中的类?,c#,oop,inheritance,type-safety,C#,Oop,Inheritance,Type Safety,我一开始就被一项看起来很简单的任务困住了。我有一个类层次结构,每个类都可以定义自己的验证规则。定义验证规则应该尽可能简单。以下是我们所需要的: class HierarchyBase { private List<Func<object, bool>> rules = new List<Func<object, bool>>(); public int fieldA = 0; public HierarchyBase()
class HierarchyBase
{
private List<Func<object, bool>> rules = new List<Func<object, bool>>();
public int fieldA = 0;
public HierarchyBase()
{
AddRule(x => ((HierarchyBase)x).fieldA % 2 == 0);
}
protected virtual void Operation()
{
fieldA++;
}
protected void AddRule(Func<object, bool> validCriterion)
{
rules.Add(validCriterion);
}
public void PerformOperation()
{
Operation();
Validate();
}
protected virtual void Operation()
{
fieldA++;
}
private void Validate()
{
IsValid = rules.All(x => x(this));
}
public bool IsValid
{
get;
private set;
}
}
类层次结构库
{
私有列表规则=新列表();
公共int fieldA=0;
公共层次结构库()
{
AddRule(x=>((HierarchyBase)x).fieldA%2==0);
}
受保护的虚拟无效操作()
{
fieldA++;
}
受保护的无效添加规则(Func validCriterion)
{
规则。添加(有效标准);
}
公共行政运作
{
操作();
验证();
}
受保护的虚拟无效操作()
{
fieldA++;
}
私有void Validate()
{
IsValid=rules.All(x=>x(this));
}
公共布尔是有效的
{
得到;
私人设置;
}
}
在添加验证规则时,还需要一件事——类型安全。否则,每个子类将不得不进行那些看起来很尴尬的造型。理想情况下,Func
会起作用,但这有一大堆问题:我们不能从任何类型的IValidatable
继承我们的HierarchyBase
,因为继承层次可以是N个层次(是的,我也能感觉到味道);将任何具体的Func
存储在规则中并遍历它们
您将如何在这里引入类型安全性?正确的方法是让层次结构中的每个类负责验证自身:
等级库:
层次结构:
层次结构:
注意:以下解决方案是我和Eric Lippert之间的一个玩笑。它是有效的,但可能不被推荐
其思想是定义一个泛型类型参数,该参数引用“当前”类型(比如这个引用“当前”对象)
等级库:
我不确定我是否理解这个问题,引入泛型并将Func
与HierarchyBase
?+1一起使用有什么不对。使用lambdas在这里没有任何好处;AddRule方法受保护,因此无法从外部注入规则集。这些规则不是类不变量,验证规则可能非常复杂。lambda只是为了简单起见,可以用ValidationRule对象代替。我们不会通过分离规则来将不同的职责与这些类混合在一起。这不是“让层次结构中的每个类负责自身验证”,而是“让层次结构中的每个类负责定义其验证规则”@dbt:在经典OOP中,要么是此继承,要么是带有e.Cancel的事件。我只是觉得OP试图得到更多的“声明性”解决方案,而不是“功能性”解决方案。啊,顺便说一句,我喜欢你基于的答案:)基思:不难想象验证规则是从数据库或XML文件加载的。我有这个解决方案,但我甚至不想注意到:)
class HierarchyBase
{
public int A { get; set; }
public bool Validate()
{
return this.OnValidate();
}
protected virtual bool OnValidate()
{
return (this.A % 2 == 0);
}
}
class HierarchyBaseInheritorA : HierarchyBase
{
public int B { get; set; }
protected override bool OnValidate()
{
return base.OnValidate() &&
(this.A > 10) &&
(this.B != 0);
}
}
class HierarchyBaseInheritorB : HierarchyBaseInheritorA
{
public int C { get; set; }
protected override bool OnValidate()
{
return base.OnValidate() &&
(this.A < 20) &&
(this.B > 0) &&
(this.C == 0);
}
}
var result = new HierarchyBaseInheritorB();
result.A = 12;
result.B = 42;
result.C = 0;
bool valid = result.Validate(); // == true
class HierarchyBase<T>
where T : HierarchyBase<T>
{
protected readonly List<Func<T, bool>> validators;
public HierarchyBase()
{
validators = new List<Func<T, bool>>();
validators.Add(x => x.A % 2 == 0);
}
public int A { get; set; }
public bool Validate()
{
return validators.All(validator => validator((T)this));
}
}
class HierarchyBaseInheritorA<T> : HierarchyBase<T>
where T : HierarchyBaseInheritorA<T>
{
public HierarchyBaseInheritorA()
{
validators.Add(x => x.A > 10);
validators.Add(x => x.B != 0);
}
public int B { get; set; }
}
class HierarchyBaseInheritorB : HierarchyBaseInheritorA<HierarchyBaseInheritorB>
{
public HierarchyBaseInheritorB()
{
validators.Add(x => x.A < 20);
validators.Add(x => x.B > 0);
validators.Add(x => x.C == 0);
}
public int C { get; set; }
}
var result = new HierarchyBaseInheritorB();
result.A = 12;
result.B = 42;
result.C = 0;
bool valid = result.Validate(); // == true