Hello!
I have a class with two overloaded methods
int Foo(int i) { Foo(i); }
int Foo(int? i) { }
First method call leads to StackOverflowException. It is OK.
Change the code so that the base class contains virtual method "int Foo(int i)" and inhereted class declares
override int Foo(int i) { Foo(i); }
int Foo(int? i) { }
After
calling the first method, a mystery occurs - the value-type argument
"i" is boxed and the second method is called instead of repeating the
first one. Why? Articel with complete source code and its IL-code is
here: http://dotnet-enthusiast.blogspot.com/2007/09/boxing-mystery-in-overloaded-and.html
Loading
angwinPosted Oct 9, 2007, 12:28 PM
You are absolutely right - there is no boxing. It occurs with "Mystery.Foo(object i)" instead of "Mystery.Foo(int i)". It is just my confusion.
AlanPosted Oct 9, 2007, 11:59 AM
Although this does seem strange at first sight, it is in fact in accordance with the complex rules which are followed by the C# compiler when deciding which of an applicable group of methods is to be called.
The critical points here are that methods marked override are ignored and methods defined in the same class as the object are favoured over methods inherited from base classes. In the event of a tie, the compiler tries to find the method which best fits the argument(s).
So, in the first case the applicable methods for the call to Foo(3) are:
private void Foo(int? i) // accessible within same class and int is implicitly convertible to int?
public new void Foo(int i) // within same class and no need for a conversion
public virtual void Foo(int i) // inherited from BaseMystery
However, the second of these is preferred because it is in the same class as the object on which it is called (i.e. 'this') and is a better fit for the actual argument of 3 than the first method.
In the second case, the applicable methods for the call to Foo(3) are:
private void Foo(int? i) // accessible within same class and int is implicitly convertible to int?
public virtual void Foo(int i) // inherited from BaseMystery
This time the first method is preferred because it is defined in the same class as the object.
The result would have been exactly the same if the first method had had a signature of:
private void Foo(double? i)
Of course, when mystery.Foo(3) is called from Main(), the first method is not accessible and so the virtual method in BaseMystery is chosen which results in a call to its override in the Mystery class because that is the runtime type of the 'mystery' variable.
Incidentally, no boxing takes place here. The int is converted to a System.Nullable which is a generic value type not a reference type.