我想要实现的目标的简化示例如下:
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
类型的字段。这可能吗?这是我做我想做的最好的方式吗?如果没有,那么解决这个问题的正确方法是什么?
答案 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
}