抽象类中的'this'类型和重载方法解析顺序混淆

时间:2012-05-14 05:51:03

标签: c# java overloading method-resolution-order

这个非常简单的例子使我感到困惑:

public class X {
    public void XMethod(A a) {
        Console.WriteLine(a.GetType());
        Console.WriteLine("Got A");
    }

    public void XMethod(B b) {
        Console.WriteLine(b.GetType());
        Console.WriteLine("Got B");
    }
}

public abstract class A {
    public virtual void M(X x) {
        Console.WriteLine(this.GetType());
        x.XMethod(this);
    }
}

public class B : A {

}

class Program {
    static void Main(string[] args) {
        X x = new X();
        B b = new B();
        b.M(x);
    }
}

输出

B
B
Got A

直到'得到'的一切都很好。当我在类X.XMethod(B)的实例上调用方法M时,我希望调用方法B

这里发生了什么?当明确提供的参数类型为XMethod(A)而不是XMethod(B)时,为什么B被调用而不是A

PS:我在java中获得了相同的输出。

3 个答案:

答案 0 :(得分:3)

只有A.M方法A不一个,B一个。

对于所有实例,IL在A.M中是相同的;在编译时,A.M仅知道thisA(或object),因此它将始终解析为XMethod(A) 。此方法解析在编译时生成的IL中,并且对于子类不会更改(实际上,子类可能位于编译器甚至不知道的单独程序集中):

.method public hidebysig newslot virtual instance void M(class X x) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
    L_0006: call void [mscorlib]System.Console::WriteLine(object)
    L_000b: ldarg.1 
    L_000c: ldarg.0 
    L_000d: callvirt instance void X::XMethod(class A)
    L_0012: ret 
}

要获得所需的行为,可以使用dynamic。但不是说你应该

答案 1 :(得分:1)

this总是引用当前正在调用操作的对象...在你的情况下,如果你想调用B方法,你需要覆盖虚拟操作,因为如果你没有覆盖它,请参考方法父类..

public class B : A {  
public override void M(X x) {
         Console.WriteLine(this.GetType());
         x.XMethod(this);
     } 
} 

答案 2 :(得分:0)

我不是100%舒服,但我认为在使用两种可能类型匹配的方法重载时,总是使用“最低一”。

编辑:在hvd的评论后,我检查了一下,他是对的:
例如。以下示例:

static void Main(string[] args)
{
    string str = "bla";
    object obj = str;

    DoIt(str);
    DoIt(obj);
}

public static void DoIt(object p) { Console.WriteLine("Object!"); }
public static void DoIt(string p) { Console.WriteLine("String!"); }

打印

  

的字符串!
  对象!