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

Dan*_*ert 5 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
}
Run Code Online (Sandbox Code Playgroud)

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

public void Bite()
{
    teeth.bite()
    Console.WriteLine("Ouch")
} 
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*ert 14

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

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

abstract class Animal
{
    public abstract Cage GetCage();
}
public class Fish : Animal
{
    public override Aquarium GetCage() { ... }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Animal animal = new Mouse();
animal.Teeth = new TRexTeeth();
Run Code Online (Sandbox Code Playgroud)

合同是可以用任何种类的牙齿来召唤制定者.通过使派生类在它可以接受的内容中更具限制性,您违反了基类的契约.

所以不要这样做.

有很多方法可以让你在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; } }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您将鼠标转换为IAnimal,则会获得返回Teeth的属性,如果您通常使用鼠标,则会获得返回SmallTeeth的属性.

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

C#是否支持返回类型协方差?

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

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