基类中的C#-调用方法

基类中的C#-调用方法,c#,.net,inheritance,.net-4.0,polymorphism,C#,.net,Inheritance,.net 4.0,Polymorphism,我有两门课: 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

我有两门课:

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'
我认为这会起作用,因为

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


编辑修复代码示例。

在类
B
中重写方法时,不要使用
new
关键字。并将
A
中的方法声明为
virtual

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

Output from B Output B的输出 输出 很好地解释了这一点。(这是原始海报链接的较新版本。)该页面显示了派生类重写虚拟成员以及新成员隐藏基类成员的示例

对于新的修改器,似乎存在一些混乱。从:

虽然可以在不使用新修改器的情况下隐藏成员,但是 结果是一个警告。如果使用new显式隐藏成员,则 取消显示此警告并记录以下事实: 该版本旨在作为替代品

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

最佳实践:

  • 强烈喜欢覆盖而不是隐藏。多态调用在OO语言中是惯用的
  • 如果要隐藏成员,始终使用新修改器
  • 永远不要发布带有编译器警告的代码
  • 如果团队中的每个开发人员都同意编译器警告无法修复,请取消它
    • 当您使用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"); }
          }
      }
      

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


      不要接受这个答案,但以我的经验,以这种方式使用“new”关键字几乎总是一个错误。它的可读性较差,而且代码清晰。

      您的类A有一个写函数,而不是写线

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

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

      它的
      public void WriteLine
      not
      public void Write
      中的方法应该是
      WriteLine
      而不是
      Write
      ?New只是隐藏了基本实现,这样你仍然可以通过从基本实现显式调用基本实现修正了我在LINQPad中的代码示例。输出:
      Output from B Output
      您发布的代码确实具有您在我的机器上期望的输出。如果你的机器上没有这个输出,那么你在编译器中发现了一个bug;请发布您正在使用的编译器的确切版本号,以便我可以尝试在该版本中复制它。新建基本上是为了避免编译器警告。这对执行没有影响。如果他不能将方法设置为虚拟,因为它不是他要修改的基类,该怎么办。然后呢?他必须使用New@DustinDavis-他不必使用新的;他应该用新的。试试看。@TrueWill是的,我知道,但这是不可接受的(至少对我的团队来说)。“我要求使用New来明确这是我们的意图”。@DustinDavis-我们同意这一点。:)我的观点是关键字不会影响行为。我同意尽可能避免使用新关键字,但它的存在不会覆盖实现。它基本上是在抑制编译器警告。在不使用virtual/override的情况下重新说明方法是覆盖实现的原因,但是以非多态的方式(如@DustinDavis所示)。但我认为,两位经验丰富的开发人员对解释其行为的最佳方式表示怀疑,这一事实正好说明了它实际上是多么危险!