Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Liskov替代原则和强化验证? 公共抽象类实体 { 公共抽象IList值{get;set;} } 公共类泛型实体:实体 { 私有IList_值; 公共覆盖IList值 { 获取{返回_值;} 设置 { 验证值(值); _价值=价值; } } 受保护的虚拟void ValidateValues(IList值) { //这里有很多验证条件,如果值验证失败,将抛出。。。 } } 公共类实体:通用实体 { 受保护的覆盖无效ValidateValues(IList值) { base.ValidateValues(值); //还有一个额外的验证条件 如果(values.Count对某个抽象类>代码>验证“/COD>实例”进行引用。这是这个问题最优雅的解决方案吗?_C#_Oop_Liskov Substitution Principle - Fatal编程技术网

C# Liskov替代原则和强化验证? 公共抽象类实体 { 公共抽象IList值{get;set;} } 公共类泛型实体:实体 { 私有IList_值; 公共覆盖IList值 { 获取{返回_值;} 设置 { 验证值(值); _价值=价值; } } 受保护的虚拟void ValidateValues(IList值) { //这里有很多验证条件,如果值验证失败,将抛出。。。 } } 公共类实体:通用实体 { 受保护的覆盖无效ValidateValues(IList值) { base.ValidateValues(值); //还有一个额外的验证条件 如果(values.Count对某个抽象类>代码>验证“/COD>实例”进行引用。这是这个问题最优雅的解决方案吗?

C# Liskov替代原则和强化验证? 公共抽象类实体 { 公共抽象IList值{get;set;} } 公共类泛型实体:实体 { 私有IList_值; 公共覆盖IList值 { 获取{返回_值;} 设置 { 验证值(值); _价值=价值; } } 受保护的虚拟void ValidateValues(IList值) { //这里有很多验证条件,如果值验证失败,将抛出。。。 } } 公共类实体:通用实体 { 受保护的覆盖无效ValidateValues(IList值) { base.ValidateValues(值); //还有一个额外的验证条件 如果(values.Count对某个抽象类>代码>验证“/COD>实例”进行引用。这是这个问题最优雅的解决方案吗?,c#,oop,liskov-substitution-principle,C#,Oop,Liskov Substitution Principle,当继承者具有额外的验证条件时(检查值的计数项),这是否违反了GenericEntity用户的LSP?我认为是这样,因为先决条件已经得到加强 这是否意味着我应该删除GenericEntity类,让AEntity和BEntity都成为实体的直接继承人?但这将导致两个类中的代码重复 我还考虑了另一个选项:实体< /C> >对某个抽象类>代码>验证“/COD>实例”进行引用。这是这个问题最优雅的解决方案吗?目前没有完全“违反LSP”,因为您没有更改类的基验证。 不幸的是,其他开发人员可以重写Valida

当继承者具有额外的验证条件时(检查
值的计数
项),这是否违反了
GenericEntity
用户的LSP?我认为是这样,因为先决条件已经得到加强

这是否意味着我应该删除
GenericEntity
类,让
AEntity
BEntity
都成为
实体的直接继承人?但这将导致两个类中的代码重复


我还考虑了另一个选项:<代码>实体< /C> >对某个抽象类>代码>验证“/COD>实例”进行引用。这是这个问题最优雅的解决方案吗?

目前没有完全“违反LSP”,因为您没有更改类的基验证。 不幸的是,其他开发人员可以重写
ValidateValues
,而不调用基本方法

避免这种情况的解决方案是创建两种方法:

    public abstract class Entity 
    {
      public abstract IList<string> Values { get; set; }
    }

    public class GenericEntity : Entity 
    {
      private IList<string> _Values;
      public override IList<string> Values 
      {
        get { return _Values; }
        set 
        {
          ValidateValues(value);
          _Values = value;
        }    
      }
      protected virtual void ValidateValues(IList<string> values)
      {
        // many validation conditions here, if values validation fails, throws...
      }
    }

public class AEntity : GenericEntity 
{
  protected override void ValidateValues(IList<string> values)
  {
    base.ValidateValues(values);
    // there is an extra validation condition
    if(values.Count < 1) throw InvalidOperationException("values count!");
  }
}

public class BEntity : GenericEntity 
{
  protected override void ValidateValues(IList<string> values)
  {
    base.ValidateValues(values);
    if(values.Count < 2) throw InvalidOperationException("values count!");
  }
}
public void ValidateValues(IList值){
//这里有很多验证条件,如果值验证失败,将抛出。。。
ValidateValuesEx();
}
受保护的虚拟void ValidateValuesEx(){
//延期
}

在您的代码设计中,子类可以通过不调用
base.ValidateValues来完全绕过您的验证。我不知道这是否是一个LSP违规,但它是你应该考虑的事情。如果您做了一个小的更改,就可以确保每次调用在
GenericEntity.validateValue中发生的验证

    public void ValidateValues(IList<string> values) {
        // many validation conditions here, if values validation fails, throws...
        ValidateValuesEx();    
    }

    protected virtual void ValidateValuesEx() {
        // for extension
    }
公共类泛型实体:实体
{
私有IList_值;
公共覆盖IList值
{
获取{返回_值;}
设置
{
验证值(值);
_价值=价值;
}    
}
私有void ValidateValues(IList值)
{
//这里有很多验证条件,如果值验证失败,将抛出。。。
此.OnValidateValues(值);
}
受保护的虚拟void OnValidateValues(IList值)
{
//什么也不做。让子类重写。
}
}
}
公共类实体:通用实体
{
受保护的覆盖无效OnValidateValues(IList值)
{
如果(values.Count<1)抛出InvalidOperationException(“values Count!”);
}
}
在此代码中,GenericEntity控制对子类的验证代码的调用。而不是相反。父类验证保证始终运行,并且总是在任何子类验证之前进行


请注意,无论子类是否调用
base.OnValidateValues

,代码的工作原理都是完全相同的。如果
ValidateValues
在验证值的方式上没有语义约束(名称表明不是),那么它的验证不是一个先决条件,因此LSP不适用。您是否希望以这种方式约束它们取决于您。LSP不是自然法则。真正的问题应该是呼叫者是否能够合理地对验证是如何发生的以及什么是允许的和不允许的感到惊讶,并且没有普遍的事实。(这也是为什么“实体”在任何应用程序中都是最糟糕的东西,因为它们几乎没有通信。)“因为您不改变类基验证”-这不是真正的原因,也不是真正的原因。参见Jeroen的评论。LSP的规则是“T的所有子类型,然后T可以被子类型替换,而不改变期望的属性”。LSP以避免代码更改和强制代码扩展的方式/指南。@Jeroen的评论是绝对正确的,我不参与“逻辑”代码的一部分,我在技术上回答这个问题而不考虑其他事情也是正确的。多亏了这一点。“子类型要求:对于类型为T的对象x,让ν(x)是一个可证明的属性。那么,对于类型为S的对象y,则Ф(y)应该为真,其中S是T的子类型。”(维基百科)->“可证明”是这里的重点,我认为。如果您说“setter将进行验证,检查a、b、c”,那么这是一个可证明的属性。如果您说“setter将包含一些由相应实现确定的验证”,那么它是不可证明的。你不能为此写一个测试。哦,我从来没有这样想过这个规则,或者我对英语的理解让我走错了路。感谢您的澄清,幸运的是,这只适用于直接后代--
AEntity
现在对于从该实体继承的任何类都有相同的问题。有一个“修复”,但它并不漂亮:将
OnValidateValues
密封在
AEntity
中,并从中调用一个新的虚拟
OnValidateValuesButMoreSo
方法,根据需要对更多层重复。如果不需要更深层的继承层次结构,则将
AEntity
密封是另一种选择。否则,购买新的public class GenericEntity : Entity { private IList<string> _Values; public override IList<string> Values { get { return _Values; } set { ValidateValues(value); _Values = value; } } private void ValidateValues(IList<string> values) { // many validation conditions here, if values validation fails, throws... this.OnValidateValues(values); } protected virtual void OnValidateValues(IList<string> values) { //do nothing. Let sub-classes override. } } } public class AEntity : GenericEntity { protected override void OnValidateValues(IList<string> values) { if(values.Count < 1) throw InvalidOperationException("values count!"); } }