为什么调用这个重写方法?

时间:2013-09-27 19:05:41

标签: c# generics interface method-overriding

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都相同。

2 个答案:

答案 0 :(得分:8)

如果我们添加一些明确的强制转型来表示TTimer.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)更好。

答案 1 :(得分:4)

  

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

是的,但是根据调用参数时的方式选择方法,而不是当前指向的对象的类型。因此,例如,即使ITimeabletd,也会调用TimedDoor方法:

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

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