2

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

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

直到'Got A'之前的一切都很好。我希望当我在 class 的实例上X.XMethod(B)调用方法时会调用该方法。MB

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

PS:对于等效实现,我在 java 中得到了相同的输出。

4

3 回答 3

3

只有 onA.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. 不过,并不是说你应该

于 2012-05-14T05:57:07.173 回答
1

this总是引用正在调用操作的当前对象...在这种情况下,如果您想调用 B 方法,则需要覆盖虚拟操作,因为如果您不覆盖它,则仅引用方法父类..

public class B : A {  
public override void M(X x) {
         Console.WriteLine(this.GetType());
         x.XMethod(this);
     } 
} 
于 2012-05-14T05:57:05.137 回答
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!"); }

印刷

细绳!
目的!

于 2012-05-14T05:58:14.437 回答