【问题标题】:Unexpected behaviour of inheritance and interfaces in c#c#中继承和接口的意外行为
【发布时间】:2009-03-03 19:48:18
【问题描述】:

今天,在用 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 = new Motorflugzeug(); (case2)我希望调用 Motorflugzeug.Starten 而不是 Flugzeug.Starten(我很确定这是 Java 显示的行为)。 openbook.galileo 说在这种情况下使用 c# 运行时类型是 Flugzeug。有什么理由吗?对我来说,这种继承行为毫无意义。
  2. 与 ILuftfahrzeug flg = new Motorflugzeug() 相同; (case3) - 在这里我可以通过让 Motorflugzeug 显式地实现 ILuftfahrzeug 来解决问题(就像在示例代码中一样)。但对我来说这是多余的,因为 Flugzeug 已经实现了 ILuftfahrzeug。
  3. 现在我想覆盖由 Starten() 调用的受保护方法 Dings()。如果我按照示例中的实现方式运行代码,则一切正常。但是如果在 Motorflugzeug 中没有实现 Starten(),则将调用基类的 Dings() 而不是 Motorflugzeug.Dings()。有人告诉我,Java 也表现出这种行为。
    有什么模式可以解决这个问题吗?否则,我将不得不覆盖调用我实际打算覆盖的方法(此处:Dings())的每个方法(此处:Starten()),即使它与基类中的完全相同。

【问题讨论】:

    标签: c# inheritance interface


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      只需确保将您希望能够覆盖的方法声明为虚拟方法。然后在继承的类上使用 override 关键字。

      更新 1: new 关键字明确了这样一个事实,即在直接使用该类时,在继承的类上声明一个非虚拟方法只会隐藏基方法。无论何时使用基类,都没有什么可隐藏的。

      【讨论】:

        【解决方案3】:

        new keywork 和 override 关键字做了两件非常不同的事情,并且您正在体验 new 的行为,从您的描述来看,我认为您希望使用 override,因为这遵循通常预期的继承行为。您需要在基类中声明方法/属性 virtual 并使用 override 而不是 new。

        哎呀,太慢了!

        【讨论】:

          【解决方案4】:

          因为你使用了“new”修饰符,见MSDN

          你应该改用“覆盖”

          【讨论】:

            【解决方案5】:

            实现的接口成员不是自动虚拟的。让它们虚拟化、抽象化等由您决定。

            【讨论】:

              【解决方案6】:

              您的程序未按预期执行的原因是因为您的方法中的 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。它几乎从不做你想做的事。

              【讨论】:

                【解决方案7】:

                我赞同 Freddy Rios 关于虚拟关键字的观点。除非您的基类使用 virtual 关键字声明方法,否则根本不会出现多态行为。使用 override 还是 new 都没有关系。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-07-31
                  • 2021-08-10
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-04-21
                  • 2023-03-04
                  • 1970-01-01
                  • 2015-10-29
                  相关资源
                  最近更新 更多