2014-09-14 1 views
0

Я недавно наткнулся на то, как компилятор C# разрешает метод вызывает методы, скрывающие методы базовых классов. Я написал следующие тесты, чтобы выставить мою проблему:C# методы сдерживания разрешения элемента во время выполнения

[TestClass] 
public class UnitTest1 
{ 
    public class Car 
    { 
     public int GetNumberOfSeets() 
     { 
      return 4; 
     } 
    } 

    public class BmwZ4 : Car 
    { 
     public new int GetNumberOfSeets() 
     { 
      return 2; 
     } 
    } 

    [TestMethod] 
    public void TestBmwNumberOfSeets1() 
    { 
     BmwZ4 bmw = new BmwZ4(); 
     Assert.AreEqual(2, bmw.GetNumberOfSeets()); 
    } 

    [TestMethod] 
    public void TestBmwNumberOfSeets2() 
    { 
     var bmw = new BmwZ4(); 
     Assert.AreEqual(2, bmw.GetNumberOfSeets()); 
    } 

    [TestMethod] 
    public void TestBmwNumberOfSeets3() 
    { 
     Car bmw = new BmwZ4(); 
     Assert.AreEqual(2, bmw.GetNumberOfSeets()); 
    } 
} 

Удивительно TestBmwNumberOfSeets1 и TestBmwNumberOfSeets2 работают прекрасно, где, как TestBmwNumberOfSeets3 просто не работает.

Может ли кто-нибудь объяснить мне, почему использование автомобиля в качестве принимающего типа (подразумеваемый upcast) превратит мой новый BMW в простой автомобиль?

EDIT: Я понял, что с помощью скрытого механизма метод, который будет вызываться, зависит от типа переменной, вызывающей метод. Динамической отправки нет. Но почему? Компилятору было бы легко использовать динамический тип вместо статически объявленного.

Скрывающий механизм в моем сознании должен использоваться, когда нужно переопределить класс, который не запечатан и не принадлежит ему (с использованием стороннего API), и хочет создать собственное поведение для метода, который является не отмечено виртуальным. Это главная цель. Но если у вас нет динамической отправки, функция абсолютно бесполезна и очень опасна для использования.

+2

Потому что вы скрываете метод, не перекрывая его. Поскольку метод не является виртуальным, вы не получаете динамическую отправку, поэтому метод, который вы получаете, определяется тем, что у вас есть: 'Car'. – Blorgbeard

+0

НИКОГДА не используйте ключевое слово new, потому что поведение, которое вы продемонстрировали, - это то, что вы получаете в результате. Метод называется изменением в зависимости от типа переменной, используемой для ссылки на экземпляр подкласса, используя применение нового модификатора к методу базового класса. Это чрезвычайно опасный код, особенно в руках вашего среднего разработчика, который не понимает нюансов языка C#. – Mick

+0

Я знаю, что это плохая привычка использовать скрытый механизм над наследованием. Но я использовал его, потому что имел дело с кодом, который не принадлежит мне, что является именно тем случаем использования этой функции языка. Но я согласен, что НИКОГДА не буду использовать его снова. Это сломанная функция! –

ответ

0

Если вы

public class Car 
{ 
    public virtual int GetNumberOfSeets() 
    { 
     return 4; 
    } 
} 

Тогда

public class BmwZ4 : Car 
{ 
    public override int GetNumberOfSeets() 
    { 
     return 2; 
    } 
} 

Ваши тесты будут проходить. Поскольку ваш код стоит сейчас, ваши тестовые тесты ошибочны. Поскольку вы явно указываете, что это Car, а не BmwZ4.

Это называется Subtype Polymorphism

+0

Это неполное объяснение и, как правило, вводящий в заблуждение – Mick

+0

Не стесняйтесь редактировать этот пост и сделать его более ясным. Я пытаюсь понять, что его ожидание того, что нового делает, на самом деле является виртуальным/переопределением. – AlexanderBrevig

+0

Демонстрация того, как ключевое слово new ведет себя для полного ответа – Mick