C# Method overloading trivia

The overload resolution rules in C# can be a bit tricky. Following is a code snippet which finds the Max between 2 numbers. using the System.Math libraries.
 
  1. public double Max(double d1, double d2)  
  2. {  
  3.     Console.WriteLine("In Max(double,double)");  
  4.     return Math.Max(d1, d2);  
  5. }  
  6.   
  7. public int Max(int i1, int i2)  
  8. {  
  9.     Console.WriteLine("In Max(int,int)");  
  10.     return Math.Max(i1, i2);  
  11. }  
  12.   
  13. public T Max<T>(T t1, T t2) where T : IComparable<T>  
  14. {  
  15.     Console.WriteLine("In Max<T,T>");  
  16.     return t1.CompareTo(t2) > 0 ? t1 : t2;  
  17. }  
  18.   
  19. static void Main(string[] args)  
  20. {   
  21.     Program p = new Program();  
  22.     Console.WriteLine(p.Max(12.1, 12.2));  
  23.     Console.WriteLine(p.Max(1.2, 2.0f));  
  24.     Console.WriteLine(p.Max(1,2.0f));  
  25. }  
Can you guess what the output is?
-The first call to Max goes to Max(double,double).
-The second call to Max goes to Max(double,double) as well since the first paramter is a double and the 2nd paramter is of type float and implicitly convertible to double.
-The third call to Max goes to Max<float> since 1 parameter(float in this case) can be substituted for T
(no coersion is needed) and the compiler is able to implicitly coerce the 2nd parameter int into a float hence the compiler sets T = float. A generic method is always a better match.

If we were to comment out Max<T> , Max(int,int) and Max(double,double) would be the only methods available in the method group. Clearly Max(double,double) is a better match since both int and float are implicitly convertible to double and hence Max(double,double) is the only unique candidate in the method group.

If we introduce a Max(int,float) then that would be considered the best match for the 3rd call to Max instead, since no type coersion of any kind would be needed.
 
  1. public double Max(double d1, double d2)  
  2. {  
  3.     Console.WriteLine("In Max(double,double)");  
  4.     return Math.Max(d1, d2);  
  5. }  
  6.   
  7. public int Max(int i1, int i2)  
  8. {  
  9.     Console.WriteLine("In Max(int,int)");  
  10.     return Math.Max(i1, i2);  
  11. }  
  12.   
  13. public float Max(int i1, float i2)  
  14. {  
  15.     Console.WriteLine("In Max(int,float)");  
  16.     return Math.Max(i1, i2);  
  17. }  
  18.   
  19. public T Max<T>(T t1, T t2) where T : IComparable<T>  
  20. {  
  21.     Console.WriteLine("In Max<T,T>");  
  22.     return t1.CompareTo(t2) > 0 ? t1 : t2;  
  23. }  
  24.   
  25. static void Main(string[] args)  
  26. {   
  27.     Program p = new Program();  
  28.     Console.WriteLine(p.Max(12.1, 12.2));  
  29.     Console.WriteLine(p.Max(1.2, 2.0f));  
  30.     Console.WriteLine(p.Max(1,2.0f));  
  31. }  
To make things interesting, let's add a generic extension method called Max.
 
  1. public static class Extensions  
  2. {  
  3.     public static T Max<T>(this Program p, T t1, T t2) where T : IComparable<T>  
  4.     {  
  5.         Console.WriteLine("In Extension Method Max<T,T>");  
  6.   
  7.         return t1.CompareTo(t2) > 0 ? t1 : t2;  
  8.     }      
  9. }  
  10.   
  11. public class Program  
  12. {  
  13.     public double Max(double d1, double d2)  
  14.     {  
  15.         Console.WriteLine("In Max(double,double)");  
  16.         return Math.Max(d1, d2);  
  17.     }  
  18.   
  19.     public int Max(int i1, int i2)  
  20.     {  
  21.         Console.WriteLine("In Max(int,int)");  
  22.         return Math.Max(i1, i2);  
  23.     }  
  24.   
  25.     public T Max<T>(T t1, T t2) where T : IComparable<T>  
  26.     {  
  27.         Console.WriteLine("In Max<T,T>");  
  28.         return t1.CompareTo(t2) > 0 ? t1 : t2;  
  29.     }  
  30.   
  31.     static void Main(string[] args)  
  32.     {   
  33.         Program p = new Program();  
  34.         Console.WriteLine(p.Max(12.1, 12.2));  
  35.         Console.WriteLine(p.Max(1.2, 2.0f));  
  36.         Console.WriteLine(p.Max(1,2.0f));  
  37.     }  
  38. }  
What should the output be now? Turns out that the extension method is never invoked.
Instance methods are always given first preference, including methods that could be a unique match by implicitly coercing types. Comment out the generic instance method and the 3rd call to Max goes to Max(double,double) instead of the extension method.
 
  1. public static class Extensions  
  2. {  
  3.     public static T Max<T>(this Program p, T t1, T t2) where T : IComparable<T>  
  4.     {  
  5.         Console.WriteLine("In Extension Method Max<T,T>");  
  6.   
  7.         return t1.CompareTo(t2) > 0 ? t1 : t2;  
  8.     }      
  9. }  
  10.   
  11. public class Program  
  12. {  
  13.     public double Max(double d1, double d2)  
  14.     {  
  15.         Console.WriteLine("In Max(double,double)");  
  16.         return Math.Max(d1, d2);  
  17.     }  
  18.   
  19.     public int Max(int i1, int i2)  
  20.     {  
  21.         Console.WriteLine("In Max(int,int)");  
  22.         return Math.Max(i1, i2);  
  23.     }  
  24.      
  25.     static void Main(string[] args)  
  26.     {   
  27.         Program p = new Program();  
  28.         Console.WriteLine(p.Max(12.1, 12.2));  
  29.         Console.WriteLine(p.Max(1.2, 2.0f));  
  30.         Console.WriteLine(p.Max(1,2.0f));  
  31.     }  
  32. }  
Happy overloading...

kick it on DotNetKicks.com

Print | posted @ Thursday, November 20, 2008 9:43 PM

Comments on this entry:

No comments posted yet.

Post A Comment
Title:
Name:
Email:
Comment:
Verification: