使用更多派生类型覆盖子类继承的属性

时间:2016-02-21 14:58:05

标签: c# inheritance

我想要实现的目标的简化示例如下:

public class Animal
{
    public virtual Teeth teeth {get;set;}
}

public class Mouse : Animal
{
    public override SmallTeeth teeth {get; set;} // SmallTeeth Inherits from Teeth
}

这显然不起作用,因为牙齿必须与要在Mouse类中重写的Animal类中的相同类型。但是,在允许在从Animal继承的任何函数中使用更多派生类型的情况下,可以实现这样的事情吗?例如,如果Animal类包含一个咬合函数:

public void Bite()
{
    teeth.bite()
    Console.WriteLine("Ouch")
} 

我可以调用从Animal继承的Bite()函数,它将使用Mouse类' SmallTeeth类型的字段。这可能吗?这是我做我想做的最好的方式吗?如果没有,那么解决这个问题的正确方法是什么?

2 个答案:

答案 0 :(得分:12)

您想要的功能称为返回类型协方差,而C#不支持它。 (顺便说一句,C ++确实如此。)

协变返回类型的常见情况是:

abstract class Animal
{
    public abstract Cage GetCage();
}
public class Fish : Animal
{
    public override Aquarium GetCage() { ... }
}

这不合法,但如果它是合法的,则安全。也就是说,如果你手中有一只动物,并且你要求一只笼子,即使它是一条鱼,你也会得到它。为什么?因为水族馆是一种笼子。

你提出的建议不仅非法,而且不安全:

Animal animal = new Mouse();
animal.Teeth = new TRexTeeth();

合同是可以用任何种类的牙齿召唤制定者。通过使派生类更容易接受它,你违反了基类的契约。

所以不要这样做。

有很多方法可以让你在C#中实现你想要的东西。

这里只是其中之一:

interface IAnimal
{
    Teeth Teeth { get; } // READ ONLY
}

class Mouse : IAnimal
{
    private SmallTeeth smallTeeth;
    public SmallTeeth Teeth 
    {
        get { return smallTeeth; }
    }

    Teeth IAnimal.Teeth { get { return this.Teeth; } }
}

现在,如果你将鼠标转换为IAnimal,你将获得返回Teeth的属性,如果你正常使用鼠标,你将获得返回SmallTeeth的属性。

我在这里描述了另一种解决这个问题的方法:

Does C# support return type covariance?

另一个答案中给出的通用解决方案也有效,但我个人更喜欢将泛型保留在其中,除非必要。

在C#"中搜索"返回类型协方差。有关此模式的更多信息。

答案 1 :(得分:3)

其实是的。您可能不应为此目的使用generics,包括类型约束(请参阅下面的评论 {{3 } 谁详细解释了你想要或想要在你的情况下实现的目标):

public class Animal<T>  where T : Teeth
{
    public virtual T teeth {get;set;}
}

public class Mouse : Animal<SmallTeeth>
{
    public override SmallTeeth teeth {get; set;} // SmallTeeth Inherits from Teeth
}