继承、隐藏和覆盖

Inheritance, hiding and overriding

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

我有以下 类:

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 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;
    }
}

但是,这是对继承的滥用,我不推荐这样做。

您所描述的行为是设计使然,您不应该试图违背它。

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

你几乎总是想避免强制转换某些东西以查看底层类型是什么。这违背了继承和强类型的目的。我们可以让我们所有的方法参数 object 然后尝试转换它们以查看它们是什么类型。如果您发现自己必须这样做,则表明出现了问题,最好在继续之前回溯并解决问题。

不清楚 Show 是什么,但也许那应该是 BasicProject 的一个方法,AdvancedProject 可以覆盖它。或者这两个 classes 有一个方法可以产生一些输出(比如值的集合)并且 Show 调用该方法并对这些值执行某些操作。

这样 Show 就不必知道它是在与 BasicProject 还是 AdvancedProject 通话。它只是调用了 class 的一个方法,结果根据它正在与之交谈的类型而有所不同。这就是多态。您与您所了解的类型 (BasicProject) 进行交互,而不知道您实际上是否在处理继承的 class。您只想 "know" 传递给方法的类型。

例如:

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,这就是您需要知道的全部内容。