这个非常简单的例子使我感到困惑:
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中获得了相同的输出。
答案 0 :(得分:3)
只有A.M
方法。 A
不一个,B
一个。
对于所有实例,IL在A.M
中是相同的;在编译时,A.M
仅知道this
为A
(或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!"); }
打印
的字符串!
对象!