[英]C# method overload with inheritance
I always thought C# resolves method calls dynamically during runtime by looking at the runtime type of the method call receiver (ie the object before the dot).我一直认为 C# 是通过查看方法调用接收者的运行时类型(即点之前的对象)来动态解析方法调用的。
However the following code sample works differently.但是,以下代码示例的工作方式不同。 If I use GenericSpaceShip in the code it returns "Generic";
如果我在代码中使用 GenericSpaceShip,它会返回“Generic”; if I use SpaceShip it returns "Specific".
如果我使用 SpaceShip,它会返回“Specific”。 Note that the runtime type in both cases is SpaceShip.
请注意,这两种情况下的运行时类型都是 SpaceShip。
So my question is: How does C# resolve the Visit method call and why does it look at the compile time rather than the runtime type in this situation?所以我的问题是:C# 如何解决 Visit 方法调用,为什么在这种情况下它查看编译时间而不是运行时类型?
Note that the two Visit methods have different parameters.请注意,这两个 Visit 方法具有不同的参数。 As Patko points out, this means I cannot use virtual/override here.
正如 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
}
}
If you want to have really dynamic resolution, then you have to use dynamic
keyword, like so:如果你想要真正的动态分辨率,那么你必须使用
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
}
In this case behaviour will be something like you have described - type of the parameter matters.在这种情况下,行为将类似于您所描述的 - 参数类型很重要。 But what you most likely want is to have a method override, like so:
但是你最有可能想要的是有一个方法覆盖,像这样:
class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public override void Visit(GenericPlanet planet)
{
Console.WriteLine("Specific");
}
}
In this case the Specific method will be called if you have an instance of SpaceShip
and Generic method for instance of GenericSpaceShip
, regardless of planet type.在这种情况下,如果您有
SpaceShip
的实例和GenericSpaceShip
实例的 Generic 方法,则无论行星类型如何,都将调用特定方法。 In this case type of the ship matters:在这种情况下,船舶类型很重要:
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
}
You would always get Generic
if GenericSpaceShip
was used instead.如果使用
GenericSpaceShip
,您将始终获得Generic
。
C# has two ways of doing it: C#有两种实现方式:
This gives you maximum control over the method resolution process, but it also requires that you tell the compiler of your decision.这使您可以最大程度地控制方法解析过程,但它也要求您将您的决定告诉编译器。
In your code the method in the derived class hides the method in the base class.在您的代码中,派生类中的方法隐藏了基类中的方法。 Here is how to modify your code to make it an override:
以下是修改代码以使其成为覆盖的方法:
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");
}
}
Note the two things that need to happen:请注意需要发生的两件事:
GenericPlanet
; you can cast it if necessary).GenericPlanet
;如果需要,您可以GenericPlanet
)。virtual
and override
to tell the compiler that the two methods are related.virtual
和override
来告诉编译器这两个方法是相关的。In C# you have to declare your methods explicitely as virtual/abstract and override if you want to override them in a derived class.在 C# 中,如果要在派生类中覆盖它们,则必须明确地将方法声明为虚拟/抽象和覆盖。
So it should read所以它应该读
class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}
class SpaceShip : GenericSpaceShip
{
public override void Visit(Planet planet)
{
Console.WriteLine("Specific");
}
}
virtual and override are the keywords you're looking for. 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");
}
}
You are using inheritance for method overloading, which means you are just keeping two methods with different signatures in the base class(SpaceShip) and derived class(GenericSpaceShip).您正在使用继承进行方法重载,这意味着您只是在基类(SpaceShip)和派生类(GenericSpaceShip)中保留两个具有不同签名的方法。
Indirectly derived class objects will always have these two methods with a different signature and, this is going to check at compile time.间接派生类对象将始终具有这两个具有不同签名的方法,这将在编译时进行检查。 You are not overriding any method having the same signature and return type, so there will not be any run-time or dynamic check.
您不会覆盖任何具有相同签名和返回类型的方法,因此不会有任何运行时或动态检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.