2009-03-03 3 views
2

Сегодня, выполняя некоторые тестовые классы в C#, я наткнулся на некоторые вопросы относительно наследования (и интерфейсов) в C#. Ниже приведен пример кода для иллюстрации моих вопросов.Неожиданное поведение наследования и интерфейсов в C#

interface ILuftfahrzeug 
{ 
    void Starten(); 
} 

class Flugzeug : ILuftfahrzeug 
{ 
    public void Starten() 
    { 
     Console.WriteLine("Das Flugzeug startet, "+Dings()); 
    } 

    protected string Dings() 
    { 
     return "Flugzeug Dings"; 
    } 
} 


class Motorflugzeug : Flugzeug, ILuftfahrzeug 
{ 
    public new void Starten() 
    { 
     Console.WriteLine("Das Motorflugzeug startet, "+Dings()); 
    } 

    protected new string Dings() 
    { 
     return "Motorflugzeug Dings"; 
    } 
} 

class InterfaceUndVererbung 
{ 
    static void Main(string[] args) 
    { 
     //Motorflugzeug flg = new Motorflugzeug(); // case1: returns "Das Motorflugzeug startet, Motorflugzeug Dings" 
     //Flugzeug flg = new Motorflugzeug(); // case2: returns "Das Flugzeug startet, Flugzeug Dings" 
     ILuftfahrzeug flg = new Motorflugzeug(); // case3: returns "Das Motorflugzeug startet, Motorflugzeug Dings" 
        // if Motorflugzeug implements ILuftfahrzeug explicitly, 
        // otherwise "Das Motorflugzeug startet, Motorflugzeug Dings" 

     flg.Starten(); 
     Console.ReadLine(); 
    } 
} 

Вот мои вопросы:

  1. объявление и инициализация с Flugzeug FLG = новый Motorflugzeug(); (case2) Я ожидал, что Motorflugzeug.Starten вызывается вместо Flugzeug.Starten (и я уверен, что это поведение Java-шоу). openbook.galileo говорит, что в этом случае с использованием C# runtime-type - Flugzeug. Есть ли причина для этого? Для меня такое наследование не имеет смысла.
  2. То же самое с ILuftfahrzeug flg = new Motorflugzeug(); (case3) - здесь я мог бы обойтись, позволив Motorflugzeug явно реализовать ILuftfahrzeug (как в примере кода). Но для меня это лишнее, так как Flugzeug уже реализует ILuftfahrzeug.
  3. Теперь я хочу перезаписать защищенные методы Dings(), которые вызывается Starten(). Если я запустил код, как он реализован в примере, все работает отлично. Но если Starten() не реализован в Motorflugzeug, вместо Motorflugzeug.Dings() будет вызываться Dings() базового слоя. Мне сказали, что Java также показывает это поведение.
    Есть ли какой-нибудь шаблон, чтобы обойти это? В противном случае мне пришлось бы перезаписать каждый метод (здесь: Starten()), который вызывает метод, который я на самом деле намерен перезаписать (здесь: Dings()), даже если он точно такой же, как в базовом классе.

ответ

9

1: вы повторно объявить метод (new); если вы override, он должен работать. new нарушает любое полиморфное поведение.

2: вы переустройство интерфейс; это действительно называет наивысшую реализацию. Опять же, override исправит это.

class Flugzeug : ILuftfahrzeug { 
    public virtual void Starten() { 
     Console.WriteLine("Das Flugzeug startet, " + Dings()); 
    }  
    protected virtual string Dings() { 
     return "Flugzeug Dings"; 
    } 
} 
class Motorflugzeug : Flugzeug { 
    public override void Starten() { 
     Console.WriteLine("Das Motorflugzeug startet, " + Dings()); 
    }  
    protected override string Dings() { 
     return "Motorflugzeug Dings"; 
    } 
} 
1

Просто убедитесь, что объявили метод, который вы хотите переопределить как виртуальный. Затем вы используете ключевое слово override в унаследованном классе.

Обновление 1: Новое ключевое слово делает явным тот факт, что просто объявление не виртуального метода в унаследованном классе просто скроет базовый метод при непосредственном непосредственном взаимодействии с этим классом. Всякий раз, когда вы работаете с базовым классом, скрывать нечего.

0

новое ключевое слово и ключевое слово переопределить делают две очень разные вещи, и вы испытываете поведение нового, откуда из вашего описания я думаю, что вы хотите использовать переопределение, поскольку это следует обычно ожидаемым поведенческим поведениям. Вам нужно будет объявить метод/свойство virtual в базовом классе и использовать переопределение, а не новое.

doh, слишком медленно!

0

Это потому, что вы используете «новый» модификатор см MSDN

Вы должны использовать «переопределение» вместо

0

Реализовано члены интерфейса автоматически не виртуальные. Это зависит от вас, чтобы сделать их виртуальными, абстрактными и т. Д.

0

Причина, по которой ваша программа не делает то, что вы ожидаете от нее, из-за ключевого слова new в вашем методе.

C# метод по умолчанию не связан динамически. Это означает, что метод, который вызывается, определяется во время компиляции. Вы можете посмотреть как тип переменной определяет, какой метод вызывается вместо фактического объекта позади него в памяти.

Для достижения желаемого эффекта вам необходимо убедиться, что c3 динамически связывает метод. вы можете сделать что-то, объявив метод virtual и метод переопределения override.

class Flugzeug : ILuftfahrzeug 
{ 
    public virtual void Starten() 
    { 
     Console.WriteLine("Das Flugzeug startet, "+Dings()); 
    } 

    protected virtual string Dings() 
    { 
     return "Flugzeug Dings"; 
    } 
} 


class Motorflugzeug : Flugzeug, ILuftfahrzeug 
{ 
    public override void Starten() 
    { 
     Console.WriteLine("Das Motorflugzeug startet, "+Dings()); 
    } 

    protected override string Dings() 
    { 
     return "Motorflugzeug Dings"; 
    } 
} 

В общем, никогда не используйте new по методу. Он почти никогда не делает то, что вы хотите.

0

I второй пункт Фредди Риоса о виртуальном ключевом слове. Если ваш базовый класс не объявит метод с ключевым словом virtual, полиморфического поведения вообще не будет. Неважно, используете ли вы переопределение или новое.

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