2013-09-27 2 views
4
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 - это то же самое в обоих случаях во время выполнения.

+1

В разрешении перегрузки C# выполняется только компилятором только * тело метода *; в C# компилятор не знает, какой тип вы собираетесь использовать для создания общего. C# generics являются * generic *, они не являются * шаблонами *, как на C++, где новая копия кода шаблона анализируется с нуля на каждой конструкции. –

+1

Кажется, вы обменяли строки, когда описываете, под кодом, что метод 'Init' возвращает в двух случаях. –

+0

@ JeppeStigNielsen фиксированный. спасибо – db42

ответ

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).

4

TimedDoorObject - то же самое в обоих случаях во время выполнения.

Правда, но метод выбирается в зависимости от того, какой параметрнабирается, как при вызове, а не тип объекта в настоящее время он указывает. Так, к примеру, это будет вызывать метод ITimeable даже если td является TimedDoor:

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

В контексте базового класса, TimedDoorObject поле набирается в ITimeable. Переопределенный Init ссылается на поле TimedDoorObject производного класса, которое напечатано как TimedDoor.

+1

Исправить. Если бы он хотел иметь другое поведение, когда это был фактический тип времени выполнения, который имел значение, а не тип времени компиляции, он мог бы использовать Timer.Add ((динамический) TimedDoorObject); 'внутри виртуального метода. Конечно, это медленнее, потому что логика разрешения перегрузки должна запускаться во время выполнения. –

Смежные вопросы