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
都相同。
答案 0 :(得分:8)
如果我们添加一些明确的强制转型来表示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)
更好。
答案 1 :(得分:4)
在运行时两种情况下,TimedDoorObject都是相同的。
是的,但是根据调用参数时的方式选择方法,而不是当前指向的对象的类型。因此,例如,即使ITimeable
为td
,也会调用TimedDoor
方法:
TimeDoor td = new TimedDoor();
Timer.Add((ITimeable)td);
在基类的上下文中,TimedDoorObject
字段的类型为ITimeable
。被覆盖的Init
引用派生类的TimedDoorObject
字段,该字段的类型为TimedDoor
。