3
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"

但是如果 Client 没有覆盖 Init(),

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

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

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

4

2 回答 2

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代表 aTimedDoor所以它使用该void Add(TimedDoor obj)函数,因为它比void Add(ITimeable obj).

于 2013-09-27T19:12:15.363 回答
4

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

是的,但是方法是根据调用时参数的类型来选择的,而不是它当前指向的对象的类型。因此,例如,ITimeable即使td是 a ,也会调用该方法TimedDoor

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

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

于 2013-09-27T19:35:21.603 回答