2015-06-22 3 views
2

Я пытаюсь понять концепцию затенения в C#. Это мой код, который не ведет себя, как я ожидать, что это:Затенение в C# - базовый метод вызывается вместо производного

public class Animal 
{ 
    public virtual void Foo() 
    { 
     Console.WriteLine("Foo Animal"); 
    } 
} 

public class Dog : Animal 
{ 
    public new void Foo() 
    { 
     Console.WriteLine("Foo Dog"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Dog dog1 = new Dog(); 
     ((Animal)dog1).Foo(); 
     Animal dog2 = new Dog(); 
     dog2.Foo(); 
    } 
} 

Когда код в Main выполняется, Foo() из базового класса (Animal) называется, и от того, что я читал о слежке, Foo() от Dog следует называть. Может кто-нибудь объяснить, что мне не хватает?

Мой пример в соответствии с этим: https://msdn.microsoft.com/en-us/library/ms173153.aspx

UPDATE: Это пример из MSDN:

class Program 
{ 
    static void Main(string[] args) 
    { 
     BaseClass bc = new BaseClass(); 
     DerivedClass dc = new DerivedClass(); 
     BaseClass bcdc = new DerivedClass(); 

     // The following two calls do what you would expect. They call 
     // the methods that are defined in BaseClass. 
     bc.Method1(); 
     bc.Method2(); 
     // Output: 
     // Base - Method1 
     // Base - Method2 


     // The following two calls do what you would expect. They call 
     // the methods that are defined in DerivedClass. 
     dc.Method1(); 
     dc.Method2(); 
     // Output: 
     // Derived - Method1 
     // Derived - Method2 


     // The following two calls produce different results, depending 
     // on whether override (Method1) or new (Method2) is used. 
     bcdc.Method1(); 
     bcdc.Method2(); 
     // Output: 
     // Derived - Method1 
     // Base - Method2 
    } 
} 

class BaseClass 
{ 
    public virtual void Method1() 
    { 
     Console.WriteLine("Base - Method1"); 
    } 

    public virtual void Method2() 
    { 
     Console.WriteLine("Base - Method2"); 
    } 
} 

class DerivedClass : BaseClass 
{ 
    public override void Method1() 
    { 
     Console.WriteLine("Derived - Method1"); 
    } 

    public new void Method2() 
    { 
     Console.WriteLine("Derived - Method2"); 
    } 
} 

Когда bcdc.Method1() выполняется, Method1() из производного класса вызывается, который ISN» Случай в моем примере.

+1

Каких точный бит заставляет ожидать, что 'Foo()' 'метод из Dog' будет называться? В обоих случаях вы вызываете его через выражение с типом времени компиляции 'Animal'. –

+0

Возможный дубликат [C#: новый или переопределение] (http://stackoverflow.com/questions/1399127/c-new-versus-override) –

+0

«Автомобиль»/«Конвертируемый автомобиль/Минивэн» показывает, что вы пытаясь сделать. На той же странице. – xanatos

ответ

0

В вашем случае, dog1 который является Dog будет обычно вам «Foo Dog», а потому, что вы явно сказать ему, чтобы быть Animal, он отображает «Foo Animal». Имеет смысл.

Затем с dog2, который является Animal, вы ожидаете, что «Foo животное», чтобы стрелять, потому что вы сказали: «Эй, ты животное», и даже если у вас есть virtual на Animal (что говорит о том, что производные классы должны переопределять этот метод, а затем разрешение того, что нужно вызвать, произойдет во время выполнения в зависимости от типа), вы используете new, который скрывает его.


Все еще отлично Хорошо. В их примере bcdc имеет тип BaseClass, но во время выполнения, так как это Derived один, AND Method1 использует virtual И override, на базе и получена, получает вызов.

Потому что это method2 не является переопределением виртуального, он вызывает только тот, о котором он знает, Base один. Если вместо определения его в качестве BaseClass, он был бы DerivedClass, он нашел бы это method2

+0

Можете ли вы проверить обновление в вопросе? –

0

В вашем примере, когда вы делаете ((Animal)dog1).Foo() или dog2.Foo(), метод Foo из животных запускается на выполнение, так как при запуске приложения CLR первого поиска реализация в базе (из-за ссылки на Animal), а затем проверяет, переопределяется ли она в производном типе или нет, поскольку вы не переопределили реализацию базового класса, она вызывает базовый метод (Animal's Foo) вместо производного (Dog's Foo) в обоих случаях.

UPDATE:

Существует очень небольшая разница между переопределением и новым ключевым словом. Когда вы переопределяете, не имеет значения, какая ссылка вы используете, всегда вызывает переопределенный метод, когда объект имеет тип Derived. В случае нового ключевого слова вы не выполняете переопределение, вы фактически скрываете реализацию базового класса. Я имел в виду здесь, что вы скрываете реализацию базового класса для типа Derived, а не для базы, поэтому, когда вы используете ссылку базы для производных объект вроде
Base obj = new Derived(); он всегда вызывает базовый метод, потому что он не может найти переопределенный метод в производном.

+0

Вы можете проверить обновление в вопросе? –

+0

Выполняет метод производного класса, потому что вы переопределяете Method1. – arpitbakshi

+0

Я также обновил свой ответ, надеюсь, это ответит на ваш вопрос .. :) – arpitbakshi

0

В строке ((Animal)dog1).Foo() сначала объект dog1 будет преобразован в тип Animal from Dog. Поэтому он вызывает метод в базовом классе Animal.

Если вы используете переопределения вместо нового ключевого слова в методы Foo класса собаки, вы получите ожидаемый результат (т.е., Foo метода собаков класса будет называться).

В вашем коде Animal dog2 = new Dog();, dog2 будет создан как объект Animal вместо Dog. Таким образом, вызов метода Foo вызовет метод в классе Animal.

Вы можете вызвать методFoo в собак класса, используя следующий код ((Dog)dog2).Foo();. Здесь переход от Animal к Dog классу возможен потому, что переменная dog2 изначально создаются из конструктора класса Dog

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