【问题标题】:C# - Call Method in Base ClassC# - 基类中的调用方法
【发布时间】:2011-10-30 05:00:21
【问题描述】:

我有 2 节课:

public class A
{
    public void WriteLine(string toWrite) { Console.WriteLine(toWrite); }
}

public class B : A
{
    public new void WriteLine(string toWrite) { Console.WriteLine(toWrite + " from B"); }
}

在我的代码中,我执行以下操作:

B writeClass = new B();
writeClass.WriteLine("Output"); // I expect to see 'Output from B'
A otherClass = (A)writeClass;
otherClass.WriteLine("Output"); // I expect to see just 'Output'

我认为这会起作用,因为polymorphism.

但是,它总是每次都写入“从 B 输出”。有没有办法让它按照我想要的方式工作?

编辑修复代码示例。

【问题讨论】:

  • 它的public void WriteLine 不是public void Write
  • A 中的方法应该是WriteLine不是 Write
  • New 只是隐藏了基础实现,因此您仍然可以通过从基础中显式调用方法来调用基础实现
  • 固定代码示例在 LINQPad 中对我来说很好用。输出:Output from B Output
  • 您发布的代码确实在我的机器上具有您期望的输出。如果它在你的机器上没有这个输出,那么你在编译器中发现了一个错误;请发布您正在使用的编译器的确切版本号,以便我可以尝试在该版本中重现它。

标签: c# .net inheritance .net-4.0 polymorphism


【解决方案1】:

当您使用 NEW 从基类中“隐藏”一个方法时,您只是在隐藏它,就是这样。当您显式调用基类实现时,它仍然会被调用。

A 不包含 WriteLine,因此您需要修复它。当我修复它时,我得到了

Output from B
Output


namespace ConsoleApplication11
{
    class Program
    {
        static void Main(string[] args)
        {
            B writeClass = new B(); 
            writeClass.WriteLine("Output"); // I expect to see 'Output from B' 
            A otherClass = (A)writeClass; 
            otherClass.WriteLine("Output"); // I expect to see just 'Output' 
            Console.ReadKey();
        }
    }

    public class A
    {
        public void WriteLine(string toWrite) { Console.WriteLine(toWrite); }
    }
    public class B : A
    {
        public new void WriteLine(string toWrite) { Console.WriteLine(toWrite + " from B"); }
    }
}

【讨论】:

    【解决方案2】:

    您在 A 类上的方法是 Write,而不是 WriteLine。将其更改为相同的名称,它将按您的预期工作。我刚刚试了一下,得到:

    B 的输出
    输出

    Polymorphism (C# Programming Guide) 很好地解释了这一点。 (这是原始海报链接的较新版本。)该页面显示了派生类覆盖虚拟成员以及新成员隐藏基类成员的示例。

    新修饰符似乎有些混乱。来自documentation

    虽然您可以在不使用 new 修饰符的情况下隐藏成员,但 结果是一个警告。如果你使用 new 显式隐藏一个成员,它 抑制此警告并记录派生的事实 版本旨在作为替代品。

    注意隐藏成员不需要是虚拟的。

    最佳做法:

    • 强烈喜欢覆盖而不是隐藏。多态调用在 OO 语言中是惯用的。
    • 如果您打算隐藏成员,请始终使用新修饰符。
    • 切勿发布带有编译器警告的代码。
    • 如果您团队中的每个开发人员都同意无法修复编译器警告,请取消它。

    【讨论】:

      【解决方案3】:

      当您覆盖类B 中的方法时,不要使用new 关键字。并将A中的方法声明为virtual

      【讨论】:

      • new 基本上是为了避免编译器警告。这对执行没有影响。
      • 如果他不能将方法设置为虚拟,因为它不是他要修改的基类。然后呢?他必须使用新的
      • @DustinDavis - 他没有使用新的;他应该使用新的。试试看。
      • @TrueWill 是的,我知道,但这是不可接受的(至少对我的团队而言)。我需要使用 New 来表明这是我们的意图。
      • @DustinDavis - 我们同意这一点。 :) 我的意思是关键字不会影响行为。
      【解决方案4】:

      “new”关键字正在使 B 的 WriteLine 实现覆盖 A 的实现。

      不要接受这个作为答案,但根据我的经验,以这种方式使用“新”关键字几乎总是错误的。它的可读性较差,代码的清晰度也很混乱。

      【讨论】:

      • 我同意尽可能避免使用 new 关键字,但它的存在不会覆盖实现。它基本上是在抑制编译器警告。在不使用 virtual/override 的情况下重新声明该方法是覆盖实现的原因,但是以非多态方式(如 @DustinDavis 所示)。
      • 是的,我试图在某种程度上简化行为。但我认为,两位经验丰富的开发人员对解释其行为的最佳方式持怀疑态度,这一事实恰恰说明了它实际上是多么危险!
      【解决方案5】:

      你的 A 类有一个 Write 函数而不是 WriteLine

      public class A
      {
          public virtual void WriteLine(string toWrite) { Console.WriteLine(toWrite); }
      }
      
      public class B : A
      {
          public override void WriteLine(string toWrite) { Console.WriteLine(toWrite + " from B"); }
      }
      

      【讨论】:

        【解决方案6】:

        首先:我猜您想将两个方法都命名为“WriteLine”,但 A 类中的方法仅命名为“Write”。第二:是的,你从 A 继承了 B,但对象仍然是“B”类型,所以现在我认为你想要的不可能。

        【讨论】:

          猜你喜欢
          • 2016-10-05
          • 2015-03-30
          • 2011-03-07
          • 1970-01-01
          • 2011-01-18
          • 1970-01-01
          • 2021-12-25
          • 2014-03-22
          • 2011-08-30
          相关资源
          最近更新 更多