[英]C# method overload with inheritance
我一直認為 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
}
}
如果你想要真正的動態分辨率,那么你必須使用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
實例的 Generic 方法,則無論行星類型如何,都將調用特定方法。 在這種情況下,船舶類型很重要:
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
;如果需要,您可以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)中保留兩個具有不同簽名的方法。
間接派生類對象將始終具有這兩個具有不同簽名的方法,這將在編譯時進行檢查。 您不會覆蓋任何具有相同簽名和返回類型的方法,因此不會有任何運行時或動態檢查。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.