带有继承的c#方法重载
本文关键字:方法 重载 继承 | 更新日期: 2023-09-27 17:52:33
我一直认为c#在运行时通过查看方法调用接收者的运行时类型(即点之前的对象)来动态解析方法调用。
但是,下面的代码示例的工作方式不同。如果我在代码中使用GenericSpaceShip,它返回"Generic";如果我使用太空船,它返回"Specific"。注意,这两种情况下的运行时类型都是太空船。
所以我的问题是:c#如何解决访问方法调用,为什么它看编译时间,而不是运行时类型在这种情况下?
注意两个Visit方法有不同的参数。正如Patko指出的,这意味着我不能在这里使用virtual/override。
class GenericSpaceShip
{
public void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public void Visit(Planet planet)
{
Console.WriteLine("Specific");
}
}
class GenericPlanet { }
class Planet : GenericPlanet { }
class Starter
{
static void Main(string[] args)
{
// SpaceShip ship = new SpaceShip();
GenericSpaceShip ship = new SpaceShip();
Planet planet = new Planet();
ship.Visit(planet); // => Generic
}
}
如果你想要真正的动态分辨率,那么你必须使用dynamic
关键字,像这样:
static void Main(string[] args)
{
dynamic ship = new SpaceShip();
Planet planet = new Planet();
ship.Visit(planet); // => Specific
// also
GenericPlanet genericPlanet = new GenericPlanet();
ship.Visit(planet); // Generic
}
在这种情况下,行为将与您所描述的类似-参数的类型很重要。但是你最可能想要的是有一个方法重写,像这样:
class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public override void Visit(GenericPlanet planet)
{
Console.WriteLine("Specific");
}
}
在这种情况下,特定方法将被调用,如果你有一个SpaceShip
的实例和GenericSpaceShip
的实例的通用方法,不管行星类型。在这种情况下,船舶类型很重要:
static void Main(string[] args)
{
SpaceShip ship = new SpaceShip();
Planet planet = new Planet();
ship.Visit(planet); // => Specific
// also
GenericPlanet genericPlanet = new GenericPlanet();
ship.Visit(planet); // Specific
}
如果使用GenericSpaceShip
,您总是会得到Generic
。
c#有两种方法:
- 在运行时解析(重写) -这适用于抽象和虚拟方法,以及实现接口的方法。除此之外,这要求方法返回类型和参数相同。
- 解析在编译时(隐藏) -这适用于具有相同的名称和参数,但不是虚拟的方法。
这给了你对方法解析过程的最大控制,但是它也要求你告诉编译器你的决定。
在代码中,派生类中的方法隐藏了基类中的方法。以下是如何修改代码以使其覆盖的方法:
class GenericSpaceShip {
// Mark the base method virtual
public virtual void Visit(GenericPlanet planet) {
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip {
// Mark the overriding method as such.
// Also note that you cannot change argument types when you override:
public override void Visit(GenericPlanet planet) {
Console.WriteLine("Specific");
}
}
注意需要发生的两件事:
- 重写方法的签名必须与基方法的签名相同(因此,它们都取
GenericPlanet
;如果有必要,你可以强制转换它)。 - 你需要使用关键字
virtual
和override
告诉编译器这两个方法是相关的。
在c#中,如果你想在派生类中重写你的方法,你必须显式地将你的方法声明为虚拟/抽象和重写。
应该是
class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public override void Visit(Planet planet)
{
Console.WriteLine("Specific");
}
}
virtual和override是您要查找的关键字。
class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public override void Visit(Planet planet)
{
Console.WriteLine("Specific");
}
}
您正在对方法重载使用继承,这意味着您只是在基类(SpaceShip)和派生类(GenericSpaceShip)中保留两个具有不同签名的方法。
间接派生的类对象总是有这两个不同签名的方法,这将在编译时进行检查。您没有重写任何具有相同签名和返回类型的方法,因此不会有任何运行时或动态检查