문제

This very simple example confuses me:

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

Output of this is

B
B
Got A

Everything up until 'Got A' is fine. I would expect that method X.XMethod(B) would be called when I invoke method M on instance of class B.

What is going on here? Why is XMethod(A) called, and not XMethod(B), when it is clear that type of provided argument is B and not A?

PS: I got same output in java for equivalent implementation.

도움이 되었습니까?

해결책

There is only on A.M method. Not one for A and one for B.

The IL is the same, in A.M, for all instances; at compile-time, A.M only knows this to be A (or object), hence it resolves always to XMethod(A). This method resolution is in the IL generated at compile-time, and doesn't change for subclasses (indeed, the subclass could be in a separate assembly that the compiler doesn't even know about):

.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 
}

To get the behaviour you want, you could use dynamic. Not saying you should, though.

다른 팁

this is always refer to the current object which is invoking the operation...in you case if you want to call the B method you need to override the virtual operation because if you are not overriding it refering to the method parent class only..

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

I'm not 100% shure, but I think when using method overloading with two possible type matches always the "lowest one" is used.

EDIT: After hvd's comment I checked it and he is right:
E.g. the following example:

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

prints

String!
Object!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top