在c#中跨越继承边界重载?

时间:2012-05-28 14:30:27

标签: c# .net .net-4.0 clr

阅读 article & article - 我感到困惑。

它说:

  

如果层次结构的不同级别有两种方法,那么   即使不是“更好的功能”,也会首先选择“更深”的   会员“为电话。

另外 -

  

事实证明,如果你覆盖了孩子的基类方法   类,不算是声明它。

现在让我们回到我的问题:

<案例1
    public class Base
     {
           public virtual void  Foo(int x)  { "1".Dump();}
     }

    public class Child : Base
     {
          public void Foo(object x) { "3".Dump();}  
          public override void  Foo(int x)  { "2".Dump();}
     }


void Main()
{
    Child c = new Child();
    c.Foo(10); //emits 3
}

好的。根据文章

  

“更深”的人将首先被选中,即使它不是“更好的功能。它不计算覆盖......

所以它是正确的,程序发出“3”。 (Foo(object x)已执行)

让我们更改第1行的顺序

<案例2
          public class Base
         {
                 public virtual void  Foo(int x)  { "1".Dump();}
                 public void Foo(object x) { "3".Dump();} //<line being moved here
         }

        public class Child : Base
         {
              public override void  Foo(int x)  { "2".Dump();}
         }


    void Main()
    {
        Child c = new Child();
        c.Foo(10); //emits 2 !!!!
    }

现在发出“2”。

现在让我们将所有 int更改为object ,将所有对象更改为int

<案例3
      public class Base
    {
      public virtual void  Foo(object x)  { "1".Dump();}
      public void Foo(int x) { "3".Dump();} 
    }

    public class Child : Base
    {
         public override void  Foo(object x)  { "2".Dump();}
    }


void Main()
{
    Child c = new Child();
    c.Foo(1); //emits "3"
}

问题


问题#1:在案例2中,Child从父亲那里继承了Foo(object x)并且他也覆盖了一个方法。

我们只是这么说:

  

事实证明,如果你覆盖了孩子的基类方法   类,不算是声明它

???

事实上,在这种情况下,我们还没有宣布继承的功能......所以这里的规则是什么


问题2:在案例3中,Child从父亲那里继承了Foo(int x)并且他也覆盖了一个方法。

但现在,他选择了父亲的职能......

似乎override只有在完全匹配时才会获胜。

再次,在这种情况下这里有什么规则


3 个答案:

答案 0 :(得分:3)

在类型T中查看名称N的member lookup process(在您的案例成员Foo中,类型为Child):

首先,在T中声明的所有可访问(第3.5节)成员的集合以及T的基本类型(第7.3.1节)构造:

virtual void Foo(int x) // Base
void Foo(object x) // Base
override void Foo(int x) // Child

从集合中排除包含覆盖修饰符的声明。

virtual void Foo(int x) // Base
void Foo(object x) // Base

Argument有一个整数类型。所以,这里最好的选择是(参数类型匹配参数类型)

virtual void Foo(int x) // Base

这个方法叫做。但它是虚方法。由于virtual method invocation机制而调用它:

  

对于在类中声明或继承的每个虚方法,都存在   存在关于方法的最派生的实现   那个班。虚拟方法M的最多派生实现   对R类的尊重如下确定:

     
      
  • 如果R包含M的引入虚拟声明,那么这是M的最多派生实现。
  •   
  • 否则,如果R包含M的覆盖,则这是M的最多派生实现。
  •   
  • 否则,关于R的M的最派生实现与关于的M的最派生实现相同   R的直接基类。
  •   

关于类virtual void Foo(int x)Child方法的派生最多的实现是什么?是的,它是

override void Foo(int x) // Child

调用哪个。 第三个样本中应用了相同的规则。但是当重写方法删除后剩下两个选项时,最佳选择(由于参数类型)是非虚方法。

答案 1 :(得分:3)

发生了两件事:

  1. 当选择要调用的方法时,编译器将遵循链接文章的规则 - 即。即使较浅的方法是更具体的匹配,也会在较浅的方法之前选择更深的方法
  2. 如果调用重写方法,它将始终调用重写方法(这与选择调用哪个方法是分开的),调用基本方法的“唯一”方法是从子类并使用base.MyMethod(。 。)
  3. 所以基本上查找规则可以选择采用int的方法,如果它在更深的类上,但是当方法被调用时,如果它被覆盖,它将调用该方法在子类上采用int。

答案 2 :(得分:1)

我认为你只是通过阅读这两篇文章弄乱你的事实..它应该像任何其他正常的重写函数一样,因为在子类中没有重载,因此没有什么可供选择。让我们看看简单的例子:

public class A
{
  public virtual void Foo()
  {
    Console.WriteLine("A.Foo() called");
  }
}

public class B: A
{
  public override void Foo()
  {
    Console.WriteLine("B.Foo() called");
  }
}

void Main()
{
new B().Foo();
}

预期产量是多少?显然没有想过任何人会说B.Foo()叫。在你的情况下,同样的事情正在发生。基类有一个更好的重载方法并不重要,子类只是赢了它..不要过于复杂的东西..

关于案例3,我不完全确定这个,但这里发生的是编译器尝试隐式转换为对象,然后它发现有一个更深层次的方法具有相同的签名,因此规则

  

如果层次结构的不同级别有两种方法,那么   即使不是“更好的功能”,也会首先选择“更深”的   会员“为电话

现在一旦进入基类,它就注意到有一个更好的方法可以使用,因此调用该方法..

P.S:上述解释是基于已经观察到的结果,可能不一定是上述行为的确切原因。