Jon*_*idt 1 c# inheritance dispatch
我一直认为 C# 是通过查看方法调用接收者的运行时类型(即点之前的对象)来动态解析方法调用的。
但是,以下代码示例的工作方式不同。如果我在代码中使用 GenericSpaceShip,它会返回“Generic”;如果我使用 SpaceShip,它会返回“Specific”。请注意,这两种情况下的运行时类型都是 SpaceShip。
所以我的问题是:C# 如何解决 Visit 方法调用,为什么在这种情况下它查看编译时间而不是运行时类型?
请注意,这两个 Visit 方法具有不同的参数。正如 Patko 指出的那样,这意味着我不能在这里使用虚拟/覆盖。
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
}
}
Run Code Online (Sandbox Code Playgroud)
如果你想拥有真正的动态分辨率,那么你必须使用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
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,行为将类似于您所描述的 - 参数类型很重要。但是你最有可能想要的是有一个方法覆盖,像这样:
class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public override void Visit(GenericPlanet planet)
{
Console.WriteLine("Specific");
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,如果您有 的实例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
}
Run Code Online (Sandbox Code Playgroud)
你总是会得到GenericifGenericSpaceShip代替。