What does this code print? - Discussion
I decided to talk about this example because somebody pointed out that the behavior was surprising, and somebody else said it would make a good blog post. I think it was Ray.
There were a couple of comments in the original post that referred to other languages - VB and C++. While C# does have a lot in common with C++, there are a lot of differences as well, and this is one such area.
The rule that governs this behavior is detailed in 7.5.5.1 of the language spec, if you want the exact details, though I find it a bit hard to understand at times, so I'll do it by example instead. In the first chunk of code, we had:
A.F(int i);
B.F(object o);
and we are calling with an int. We start at the most derived class and look for methods that match our invocation. If we find any in a specific class, then we look through all applicable methods in that class and choose the best one (or error out if there isn't a best one). If we don't find any in the current class, we try the next base class.
So, because there's a conversion from int to object, B.F(object) is applicable, and we choose B.F(object o) and don't even look at A.F(int i).
Similarly, in the second case, we choose B.F(int i) rather than A.F(short i).
But note that the method in the derived class has to be an applicable one. If we do something like:
using System;
public class A
{
public void F(int i)
{
Console.WriteLine("A: {0}", i);
}
}
public class B: A
{
public void F(string s)
{
Console.WriteLine("B: {0}", s);
}
}
public class Test
{
public static void Main()
{
B b = new B();
b.F(15);
}
}
We will find out that B.F(string) isn't applicable, so we call A.F(int) instead.
So, why does C# behave this way? Well, it's because of versioning. Considering our first case again, but assume that A.F(int) wasn't there when we first developed our product. We would be calling B.F(object). If somebody comes along and adds A.F(int) later, that doesn't change our program behavior, but it would if we didn't have the rule.
Regardless of the behavior, it's a pretty bad idea to do overloaded methods where there are conversions between the types (ie short and int, or object and anything), because the conversions may cause the compiler to call a different method than you expected. If you must do this, it's a good idea to provide overloads for all the types, so that there isn't any chance of confusion.
Comments
Anonymous
December 13, 2005
Why FxCop does not support your recomendation ?Anonymous
December 13, 2005
You're right. C# does have a lot in common with C#Anonymous
December 13, 2005
Thanks me - fixed that little typo.
TAG, it would be interesting to do that in FXCop - you'd have to know the conversion rules that C# uses.Anonymous
December 13, 2005
Can the compiler not be made to issue a warning for this case (more complex than the clear shadow case where overloading is not required I admit).
Strikes me that the same lack of clarity exists which makes the warning for the non overloaded case useful.Anonymous
December 14, 2005
Eric,
Strongly agree with you. Conversion rules is something that requered to be implemented by Microsoft.
I've reported this last year ( 2004-08-11 )
http://lab.msdn.microsoft.com/ProductFeedback/viewfeedback.aspx?feedbackid=FDBK13608Anonymous
December 14, 2005
Something that I thought of was the extension methods in C# 3.0. With the method overload resolution rules they use (quite correctly) the problem with changing behaviour can be encountered. I posted a description in my blog:
http://www.hedgate.net/blog/2005/12/15/extension-methods-and-method-overload-resolution/Anonymous
October 03, 2006
PingBack from http://www.hedgate.net/articles/2005/12/15/extension-methods-and-method-overload-resolutionAnonymous
August 13, 2007
CLR Week: A new annual tradition.Anonymous
September 18, 2007
PingBack from http://www.hedgate.net/articles/2006/10/04/extension-methods-and-method-overload-resolution/