使用更多派生类型重写子类继承的属性
本文关键字:子类 继承 属性 重写 类型 派生 | 更新日期: 2023-09-27 18:35:43
我试图实现的目标的简化示例如下所示:
public class Animal
{
public virtual Teeth teeth {get;set;}
}
public class Mouse : Animal
{
public override SmallTeeth teeth {get; set;} // SmallTeeth Inherits from Teeth
}
这显然不起作用,因为牙齿必须与动物类中的类型相同才能在鼠标类中被覆盖。但是,是否可以实现这样的事情,允许我在从 Animal 继承的任何函数中使用更派生的类型?例如,如果 Animal 类包含一个咬人的函数:
public void Bite()
{
teeth.bite()
Console.WriteLine("Ouch")
}
我可以调用从 Animal 继承的 Bite()
函数,它将使用 Mouse 类的类型为 SmallTeeth
的字段。这可能吗?这是做我想做的事情的最佳方式吗?如果不是,解决这个问题的正确方法是什么?
注意:这个答案写于 2016 年。从那以后的几年里,返回类型协方差(令人惊讶!)被添加到 C# 中。阅读此答案时请记住这一点。
<小时 />所需的功能称为返回类型协方差,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,您将获得返回 Tooth 的属性,如果您正常使用鼠标,您将获得返回 SmallTooth 的属性。
我在这里描述了解决此问题的另一种方法:
C# 是否支持返回类型协方差?
另一个答案中给出的通用解决方案也有效,尽管我个人更愿意将泛型排除在外,除非必要。
搜索"C# 中的返回类型协方差"以获取有关此模式的详细信息。
其实是的。您可以但不应该为此目的使用generics
,包括类型约束(请参阅下面的评论和 Eric Lippert 的帖子,他详细解释了您在您的情况下想要或试图实现的目标):
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
}