继承,隐藏和压倒一切

时间:2017-04-24 14:06:32

标签: c# oop inheritance override virtual

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

我有以下课程:

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而不是{{1} }}

2 个答案:

答案 0 :(得分: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;
    }
}

然而,这是对遗产的滥用,我不推荐它。

答案 1 :(得分:0)

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

如果将类型为A的参数传递给方法,则该方法知道它的类型为A。实际引用可以是继承自A的类的实例,但该方法并不知道。

您几乎总是希望避免投射某些内容以查看基础类型。这违背了继承和强类型的目的。我们可以创建所有方法参数object,然后尝试转换它们以查看它们的类型。如果你发现自己必须这样做,那就表明某些事情出了问题,在继续之前回溯并解决这个问题是件好事。

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

那样Show不必知道它是否与BasicProjectAdvancedProject交谈。它只是调用类的方法,结果根据它与之交谈的类型而有所不同。这种多态性。您可以在不知道自己是否实际处理继承的类的情况下与您所知道的类型(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以及你需要知道的全部内容。