简体   繁体   中英

Unexpected behaviour of inheritance and interfaces in c#

Today, while implementing some testclasses in c#, I stumpled on some questions regarding inheritance (and interfaces) in c#. Below I have some example code to illustrate my questions.

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();
    }
}

These are my questions:

  1. Declaring and initializing with Flugzeug flg = new Motorflugzeug(); (case2) I expected that Motorflugzeug.Starten is called instead of Flugzeug.Starten (and I'm pretty sure that this is the behaviour Java shows). openbook.galileo says that in that case using c# the runtime-type is Flugzeug. Is there any reason for that? For me such inheritance behaviour makes no sense.
  2. Same with ILuftfahrzeug flg = new Motorflugzeug(); (case3) - here I could work around by letting Motorflugzeug implement ILuftfahrzeug explicitly (as it is in the example code). But for me this is redundant since Flugzeug already implements ILuftfahrzeug.
  3. Now I want to overwrite a protected methods Dings() that is called by Starten(). If I run the code as it is implemented in the example everthing works fine. But if Starten() is not implemented in Motorflugzeug, Dings() of the baseclass will be called instead of Motorflugzeug.Dings(). I was told that Java also shows this behaviour.
    Is there any pattern to get around this? Otherwise I would have to overwrite every method (here: Starten()) that calls the method that I actually intend to overwrite (here: Dings()), even if it is exactly the same as in the base class.

1: you are re-declaring the method ( new ); if you override it should work. The new breaks any polymorphic behavior.

2: you are re-implementing the interface; this indeed calls the highest implementation. Again, override would fix this.

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";
    }
}

Just make sure to declare the method that you want to be able to override as virtual. Then you use the override keyword on the inherited class.

Update 1: The new keyword is making explicit the fact, that just declaring a non virtual method on the inherited class will just hide the base method, when working with that class directly. Whenever you work with the base class, there is nothing to hide.

the new keywork and the override keyword do two very different things, and you are experiencing the behavior of new, where from your description I think you want to be using override as this follows the normally expected inherience behaviours. You will need to declare the method/property virtual in the base class and use override rather than new.

doh, too slow!

It's because you use the "new" modifier, see MSDN

You should use "override" instead

Implemented interface members are not automatically virtual. It's up to you to make them virtual, abstract, etc.

The reason your program does not do what you expect it to do is because of the new keyword in your method.

c# method are not dynamically bound by default. This means the method that is called is determined at compile time. You can look at as the type of the variable determines which method is called instead of the actual object behind it in memory.

To achieve the effect you want, you need make sure c3 dynamically bind the method. you can do thing by declaring the method virtual and the overriding method 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";
    }
}

In general, never use new on a method. It almost never does what you want.

I second Freddy Rios' point about the virtual keyword. Unless your base class declares a method with the virtual keyword there will be no polymorphic behaviour at all. It doesn't matter whether you use override or new.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM