【问题标题】:Inheritance, hiding and overriding继承、隐藏和覆盖
【发布时间】:2017-09-21 06:22:38
【问题描述】:

关于继承、隐藏和覆盖的一个小问题。

我有以下课程:

public class A
{
    public BasicProject project { get; set; }
    public int a {get; set;}
}

public class B : A 
{
    public AdvancedProject project { get; set; }
    public int b {get; set;} 
}

public class C : A
{
    public new AdvancedProject project { get; set; }
    public int c {get; set;}
}

public class BasicProject
{
    public int p1 {get; set;}
    public int p2 {get; set;}
}

public class AdvancedProject : BasicProject
{
    public int p3 {get; set;}
    public int p4 {get; set;}
}

我还有一些功能

A show(A x)
{
    x.project.p1;
    x.project.p2;
    x.project.p3;
    x.project.p4;
}

问题在于,当我将B(或C)类型的对象传递给函数时,x.project 指的是BasicProject 类型而不是AdvancedProject

【问题讨论】:

  • 那是因为方法只知道A。如果您想访问 B 属性,您应该在内部强制转换为 B 或使用泛型。
  • 那是因为projectA 中不是虚拟的,如果是,你必须在Boverride 它,即使那样它仍然必须具有相同的类型.
  • @juharr 添加虚拟/覆盖导致编译错误“类型必须是'BasicProject'才能匹配覆盖”成员'A.project'
  • @Ilan 是的,我说过类型必须相同才能覆盖它们。否则,您只能隐藏该属性,并且必须像 Zohar 所说的那样通过转换为 B 来引用它。我不确定这是否只是一个学习练习,或者这是否是你正在尝试的东西的淡化版本,但如果是后者,那么你可能想要描述你试图使用它的目的,因为这看起来像设计问题。
  • 根本问题是违反替换规则的无效设计。

标签: c# oop inheritance overriding virtual


【解决方案1】:

处理它的一种方法是:

A show(A x)
{
    x.project.p1;
    x.project.p2;
    var y = x as B;
    if(y != null)
        y.project.p3;
        y.project.p4;
    }
    var z = x as C;
    if(z != null)
        z.project.p3;
        z.project.p4;
    }
}

但是,这是对继承的滥用,我不建议这样做。

【讨论】:

    【解决方案2】:

    您所描述的行为是设计使然,您不应该尝试反对它。

    如果您将A 类型的参数传递给一个方法,该方法只知道它是A 类型。实际引用可能是从A 继承的类的实例,但该方法不知道这一点。

    您几乎总是希望避免强制转换以查看底层类型是什么。这违背了继承和强类型的目的。我们可以将所有方法参数设为object,然后尝试强制转换它们以查看它们是什么类型。如果您发现自己不得不这样做,则表明出现了问题,最好在继续之前回溯并修复它。

    不清楚Show 是什么,但也许这应该是BasicProject 可以覆盖的AdvancedProject 的方法。或者这两个类有一个方法可以产生一些输出(比如一个值的集合),Show 调用该方法并对这些值做一些事情。

    这样Show 不必知道它是在与BasicProject 还是AdvancedProject 交谈。它只是调用类的一个方法,结果根据它正在与之交谈的类型而有所不同。这就是多态性。您与您所知道的类型 (BasicProject) 进行交互,但不知道您是否真的在处理继承的类。您只想“知道”传递给方法的类型。

    例如:

    public class BasicProject
    {
        public int p1 { get; set; }
        public int p2 { get; set; }
        public virtual IEnumerable<int> GetValues()
        {
            return new [] {p1, p2};
        }
    }
    
    public class AdvancedProject : BasicProject
    {
        public int p3 { get; set; }
        public int p4 { get; set; }
    
        public override IEnumerable<int> GetValues()
        {
            var values = new List<int>(base.GetValues());
            values.Add(p3);
            values.Add(p4);
            return values;
        }
    }
    
    public class AdvancedProject : BasicProject
    {
        public int p3 {get; set;}
        public int p4 {get; set;}
    }
    

    现在你的方法Show 只是调用GetValues() 函数。如果项目是BasicProject,它会获得一组值,如果是AdvancedProject,它会获得另一组值。但它永远不需要知道该属性是哪种类型。
    并且没有任何东西可以从 A 继承。

    这是Liskov Substitution Principle 的一部分。它基本上是说,如果你有一个调用A 类型参数的方法,那么你可以替换任何继承自A 的对象的实例。您不必知道或关心实际类型是什么。就您而言,它是A,这就是您需要知道的全部内容。

    【讨论】:

      猜你喜欢
      • 2011-02-05
      • 2012-07-28
      • 1970-01-01
      • 1970-01-01
      • 2019-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多