简体   繁体   English

c#中继承和接口的意外行为

[英]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#. 今天,在c#中实现一些测试类时,我在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(); 使用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). (case2)我期望调用Motorflugzeug.Starten而不是Flugzeug.Starten(我很确定这是Java显示的行为)。 openbook.galileo says that in that case using c# the runtime-type is Flugzeug. openbook.galileo说在那种情况下使用c#运行时类型是Flugzeug。 Is there any reason for that? 有什么理由吗? For me such inheritance behaviour makes no sense. 对我来说,这种继承行为毫无意义。
  2. Same with ILuftfahrzeug flg = new Motorflugzeug(); 与ILuftfahrzeug相同flg = new Motorflugzeug(); (case3) - here I could work around by letting Motorflugzeug implement ILuftfahrzeug explicitly (as it is in the example code). (case3) - 在这里我可以让Motorflugzeug明确地实现ILuftfahrzeug(就像它在示例代码中一样)。 But for me this is redundant since Flugzeug already implements ILuftfahrzeug. 但对我而言,这是多余的,因为Flugzeug已经实施了ILuftfahrzeug。
  3. Now I want to overwrite a protected methods Dings() that is called by Starten(). 现在我要覆盖由Starten()调用的受保护方法Dings()。 If I run the code as it is implemented in the example everthing works fine. 如果我运行代码,因为它在示例中实现everthing工作正常。 But if Starten() is not implemented in Motorflugzeug, Dings() of the baseclass will be called instead of Motorflugzeug.Dings(). 但是如果在Motorflugzeug中没有实现Starten(),则将调用基类的Dings()而不是Motorflugzeug.Dings()。 I was told that Java also shows this behaviour. 我被告知Java也会显示这种行为。
    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. 否则我将不得不覆盖调用我实际打算覆盖的方法的每个方法(这里:Starten())(这里:Dings()),即使它与基类完全相同。

1: you are re-declaring the method ( new ); 1:你重新宣布方法( new ); if you override it should work. 如果你override它应该工作。 The new breaks any polymorphic behavior. new破坏了任何多态行为。

2: you are re-implementing the interface; 2:你正在重新实现界面; this indeed calls the highest implementation. 这确实称为最高的实施。 Again, override would fix this. 再次, 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";
    }
}

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. 然后在继承的类上使用override关键字。

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. 更新1:新关键字明确表示这样一个事实,即直接使用该类时,在继承的类上声明非虚方法只会隐藏基本方法。 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. 新的keywork和override关键字执行两个非常不同的事情,并且您正在体验new的行为,从您的描述中我认为您希望使用override,因为这遵循通常预期的继承行为。 You will need to declare the method/property virtual in the base class and use override rather than new. 您需要在基类中声明方法/属性virtual并使用override而不是new。

doh, too slow! 啊,太慢了!

It's because you use the "new" modifier, see MSDN 这是因为您使用“新”修饰符,请参阅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. 您的程序没有按预期执行的原因是因为方法中的new关键字。

c# method are not dynamically bound by default. 默认情况下,c#方法不是动态绑定的。 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. 要获得所需的效果,您需要确保c3动态绑定方法。 you can do thing by declaring the method virtual and the overriding method override . 你可以通过声明方法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";
    }
}

In general, never use new on a method. 通常,永远不要在方法上使用new 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. 除非你的基类使用virtual关键字声明一个方法,否则根本就没有多态行为。 It doesn't matter whether you use override or new. 无论您使用覆盖还是新建都无关紧要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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