为什么调用此重写方法

本文关键字:方法 重写 调用 为什么 | 更新日期: 2023-09-27 18:33:02

public interface ITimeable     {}
public class TimedDoor : ITimeable  {}
public static class Timer
{
    public static void Add(ITimeable obj)
    {
       Console.Write("Add with parameter - ITimeable"); 
    }
    public static void Add(TimedDoor obj)
    {
       Console.Write("Add with parameter - TimedDoor"); 
    }
}
public class BaseClient<T> where T : ITimeable
{
    public T TimedDoorObject;
    public virtual void Init()
    {
        Timer.Add(TimedDoorObject);
    }
}
public class Client : BaseClient<TimedDoor>
{
    public Client()
    {
        TimedDoorObject = new TimedDoor();
    }
    public override void Init()
    {
        Timer.Add(TimedDoorObject);
    }
}

在此Client.Init()返回"Add with parameter - TimedDoor"

但是如果客户端没有覆盖 Init(),

public class Client : BaseClient<TimedDoor>
{
    public Client()
    {
        TimedDoor = new TimedDoor();
    }
}

在这里,Client.Init()返回"Add with parameter - ITimeable"

这是怎么回事? 在运行时,这两种情况下TimedDoorObject相同。

为什么调用此重写方法

如果我们添加一些显式强制转换,表示T在调用Timer.Add(TimedDoorObject)点表示的内容,则会使正在发生的事情更加明显。

public class BaseClient<T> where T : ITimeable
{
    public T TimedDoorObject;
    public virtual void Init()
    {
        Timer.Add((ITimeable)TimedDoorObject);
    }
}
public class Client : BaseClient<TimedDoor>
{
    public Client()
    {
        TimedDoorObject = new TimedDoor();
    }
    public override void Init()
    {
        Timer.Add((TimedDoor)TimedDoorObject);
    }
}

因此,当BaseClient被遵守时,它所知道的只是T是某种ITimeable对象,因此它能够链接到的最佳重载是void Add(ITimeable obj)版本。相比之下,在编译时,Client知道T表示TimedDoor,因此它使用 void Add(TimedDoor obj) 函数,因为它比 void Add(ITimeable obj) 匹配更好。

在运行时,TimedDoorObject 在这两种情况下都是相同的。

True,但该方法是根据调用参数时键入的内容来选择的,而不是它当前指向的对象的类型。因此,例如,即使tdTimedDoor,也会调用 ITimeable 方法:

TimeDoor td = new TimedDoor();
Timer.Add((ITimeable)td);

在基类的上下文中,TimedDoorObject字段的类型为 ITimeable 。重写的Init引用派生类的 TimedDoorObject 字段,该字段类型为 TimedDoor