Reputation: 847
given the following:
class A
{
public void Foo(object o)
{
Console.WriteLine("general");
}
public void Foo(B o)
{
Console.WriteLine("specific");
}
}
class B
{
A a = new A();
public void CallFoo(object x)
{
a.Foo(x);
}
public static void Main()
{
B b = new B();
b.CallFoo(b);
b.a.Foo(b);
}
}
I observe the following output:
general
specific
So naturally, I'm baffled. What's going on here?
Upvotes: 1
Views: 236
Reputation: 66
1) b.CallFoo(b); CallFoo takes an object type as a parameter. This object is then passed to Foo and consequently Foo(object o) will get called.
2) b.a.Foo(b); Foo(B o) will get called since the object that is passed is of type B.
Upvotes: 1
Reputation: 191
It's all about the method signatures. b.CallFoo() takes in an Object, naturally, it calls the overload that is expecting an object. The next call is inputs a strong typed object of type B, the compiler knows that you want to use the overload that takes an object of type B.
If you want to conditionally call the overload based on the type, you would have to do that work yourself.
For example:
class B
{
A a = new A();
public void CallFoo(object x)
{
if (x.GetType() == typeof(B))
{
a.Foo((B)x);
}
else
{
a.Foo(x);
}
}
public static void Main()
{
B b = new B();
b.CallFoo(b);
b.a.Foo(b);
}
}
Upvotes: 0
Reputation: 3960
That's the expected behavior. In your first call b.CallFoo(b)
you are calling method B.CallFoo(object)
which in turn calls the base class's Foo(object)
The second call, you are directly accessing the Foo(B)
method from class A and you're also passing a var b of type B
Upvotes: 0
Reputation: 581
b.CallFoo(object x) is being passed as type of object if you don't check instanceof it will be treated as of type Object if you change the function of A.Foo to:
public void Foo(object o){
B test = o as B;
if(test == null){
Console.WriteLine("general");
}else
{
Console.WriteLine("specific");
}
}
you will get what you are expecting
Upvotes: 0
Reputation: 3752
This is absolutely the correct behavior. Overload resolution generally occurs a compile time, not run time. (unless you're doing some funky reflection or compiling lambda expressions ec)
In your code, at compile time, .NET only knows that x is an object:
public void CallFoo(object x)
{
a.Foo(x); // <--- Gets wired up to Foo(object o) as x is declared as an object!
}
Therefore the generic overload gets called in this case.
Conversely, in the second line, .NET knows for sure that it's a B because you declared it as such:
b.a.Foo(b); // <-- Gets wired up to Foo(B b) as declared as B!
Therefore the specific overload gets called in this case.
Upvotes: 1
Reputation: 125650
Every b.CallFoo
will result in general being printed, because CallFoo
takes object
as parameter. Correct method overload is determined during the compilation, so the general is the only one compiler can choose here.
You can force the overload to be chosen during runtime by using dynamic
as CallFoo
parameter type:
public void CallFoo(dynamic x)
{
a.Foo(x);
}
or you can write the logic by yourself, within B.CallFoo
:
public void CallFoo(object x)
{
if (x is B)
{
a.Foo((B)x);
}
else
{
a.Foo(x);
}
}
or directly within a.Foo
:
public void Foo(object o)
{
if (o is B)
{
Foo((B)o);
}
else
{
Console.WriteLine("general");
}
}
Upvotes: 5