All About Method Overloading In C#

Code used in this article for different scenarios of Method Overloading is available here on GitHUB.
Polymorphism is one of the most important pillars of object-oriented programming. It further gets categorized to static and dynamic polymorphism which respectively maps to method overloading and method overriding.
For this article, I have covered the scenario which I have seen in my professional experience and have faced being on either side of the interview table. I have tried to cover all of the possible tricks and twists with method overloading but still, a few may not be covered in this, so I will leave them on you to explore.

Return type

The basic definition of method overloading states that same method with different signatures. The compiler doesn’t consider return type. So this is a valid scenario,
  1. static void MethodOverloadingReturn()  
  2.  {  
  3.      Console.WriteLine("MethodOverloading with No Parameters");  
  4.  }  
  6.  static int MethodOverloadingReturn(string str)  
  7.  {  
  8.      Console.WriteLine("MethodOverloading with Object Parameters");  
  9.      return 0;  
  10.  }  
This will not throw any exception and compile successfully and based on the call will call the respective method. But if we have this scenario, where method name and input parameters are same, but return type is different:
  1. static void MethodOverloadingReturn(string strg)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with No Parameters");  
  5. }  
  7. static int MethodOverloadingReturn(string str)  
  8. {  
  9.     Console.WriteLine("MethodOverloading with Object Parameters");  
  10.     return 0;  
  12. }  
We will get these two errors,
  • Error CS0111 Type 'Program' already defines a member called 'MethodOverloadingReturn' with the same parameter types
  • Error CS0121 The call is ambiguous between the following methods or properties: 'Program.MethodOverloadingReturn(string)' and 'Program.MethodOverloadingReturn(string)'
So with this we conclude that ,
Same Method name, Different Input parameters, Any return type - Method Overloading

Same Method name, Same Input parameters, Different return type - Compilation Error
and it will be more clear from this table,
All About Method Overloading In C#

Different Parameters

Methods with different parameters will exhibit Method overloading. As in this case, one with no parameter and another with one input parameter.
  1. static void MethodOverloading_Diff()  
  2.  {  
  3.      Console.WriteLine("MethodOverloading with No Parameters");  
  4.  }  
  6.  static void MethodOverloading_Diff(string str)  
  7.  {  
  8.      Console.WriteLine("MethodOverloading with String Parameters");  
  9.  }  

Parameter order

Different order of parameters also enables the method overloading.
  1. static void MethodOverloading_Order(int i, string str)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with String Parameters");  
  4. }  
  6. static void MethodOverloading_Order(string str, int i)  
  7. {  
  8.     Console.WriteLine("MethodOverloading with String Parameters");  
  9. }  

Conversion between data types

Up to this point we saw simple scenarios and now this one is going to be tricky. We know C# supports implicit and explicit conversion.
In Implicit conversion, no special syntax is  required while for explicit conversion, we need to cast expression.
For numeric conversion, it follows some rules, which you can in read this MSDN article for more details.
Please note some implicit numeric conversion may lead to data loss.
For example- we will take the case of int, float and double. Integer can be implicitly converted to float and double while float can be implicitly converted to double, but for any other conversion among these 3 types, we may have to do explicit conversion.
Now let us come back to our subject and we will consider this scenario,
  1. static void MethodOverloading_Conv(int i)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with int Parameters");  
  4. }  
  6. static void MethodOverloading_Conv(double d)  
  7. {  
  8.     Console.WriteLine("MethodOverloading with double Parameters");  
  9. }  
Now I am going to call this,
  1. MethodOverloading_Conv(10);  
Since we have two methods qualifying to be called (integer can be implicitly converted to double) but in my caller method I have integer, in this case compiler will decide in which scenario conversion is better. (Yes, conversion as compiler needs to decide). So, it will call method with int parameter.
Now let us deep dive in this case,
  1. static void MethodOverloading_Conv(double d, int i)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with double, int Parameters");  
  4. }  
  6. static void MethodOverloading_Conv(int i, double d)  
  7. {  
  8.     Console.WriteLine("MethodOverloading with int,double Parameters");  
  9. }  
  11. static void MethodOverloading_Conv(int i1, int i2)  
  12. {  
  13.     Console.WriteLine("MethodOverloading with int,int Parameters");  
  14. }  
And my call is,
  1. MethodOverloading_Conv(5, 15);  
Based on the above logic of best available conversion, you can easily decide it is going to call:
MethodOverloading_Conv(int i1, int i2)
But to add another twist to it, what if I don’t have this methos available:
MethodOverloading_Conv(int i1, int i2)
Then compiler will get confused and give this error as in both methods, it must do one conversion.
Error CS0121 The call is ambiguous between the following methods or properties: 'Program.MethodOverloading_Conv(double, int)' and 'Program.MethodOverloading_Conv(int, double)'
Now it will be clearer from this example,
I have these two methods,
  1. static void MethodOverloading_Conv(int i1, int i2, double dbl)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with int,int, double Parameters");  
  4. }  
  5. static void MethodOverloading_Conv(int i1, double i2, double dbl)  
  6. {  
  7.     Console.WriteLine("MethodOverloading with int,double, double Parameters");  
  8. }  
And I am calling it from,
  1. MethodOverloading(5,5,15);  
i.e. all integer input parameters.
Now, for the first method, the compiler needs to do one conversion while the second method in the above scenario needs two conversions from int to double and hence first method (with one conversion) will be called i.e:
  1. static void MethodOverloading_Conv(int i1, int i2, double dbl)  

Object type

We all know all C# types derive from object, that means any type can be implicitly converted into object type.
Now consider this this scenario,
  1. static void MethodOverloading_Obj(string str, object obj)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with string, Object Parameters");  
  4. }  
  6. static void MethodOverloading_Obj(object obj1, object obj2)  
  7. {  
  8.     Console.WriteLine("MethodOverloading with Object,Object Parameters");  
  9. }  
And I am calling this from these two methods,
  1. Call # 1 - MethodOverloading_Obj("Atul"true);  
  2. Call # 2 - MethodOverloading_Obj(truetrue);  
The call number will call method can call both but since in the first method, one conversion is needed i.e. bool to object while for the second it will need two conversions, a string to object and a bool to object. And hence the first method will win here.
  1. static void MethodOverloading_Obj(string str, object obj)  
For Call # 2, second method will be called as compiler has no option of matching but to do 2 conversions.

Named Parameters

Now consider this scenario for understanding named parameter in method overloading –
  1. static void MethodOverloading_named(int first, int second, int third)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with int,int,int Parameters");  
  4. }  
  6. static void MethodOverloading_named(double dFirst, double dSecond, double dThird)  
  7. {  
  8.     Console.WriteLine("MethodOverloading with double,double,double Parameters");  
  9. }  
As we saw in the previous scenario that, if we normally call method with 3 input integer type parameters i.e.:
  1. MethodOverloading_named(10, 15, 14);  
It will call the first method without any doubt.
But if my calling is
  1. MethodOverloading_named(dFirst: 10, dThird: 13, dSecond: 15);  
Then despite overhead of 3 conversions, compiler will call the method with 3 double parameters.

Optional Parameters

Optional parameters in C# play an important role so I will explain this scenario as well in good detail,
  1. static void MethodOverloading_Optional(object str)  
  2. {  
  3.     Console.WriteLine("MethodOverloading with object Parameters");  
  4. }  
  6. static void MethodOverloading_Optional(string str, int x = 5)  
  7. {  
  8.     Console.WriteLine("MethodOverloading with str, int Parameters");  
  9. }  
And my call is,
  1. MethodOverloading_Optional("AKS");  
  2. MethodOverloading_Optional(true);  
For Call #1, if the compiler calls the method with one parameter then it needs to do one conversion from string to Object. If It calls the method with two parameters then it will match the first parameter but will have to add value to the optional parameter, and hence it will call the method with 2 parameters.
For Call # 2, it will call method with one parameter for obvious reasons.

Out and ref

Out and Ref are very important concepts in C#. Let us examine in this example, how they work in overloading situations.
For this code snippet,
  1. static void MethodOverloadingRef(decimal d, int a)  
  2. {  
  4.     Console.WriteLine("MethodOverloading with decimal,int Parameters");  
  5. }  
  6. static void MethodOverloadingRef(decimal d, out int a)  
  7. {  
  8.     a = 10;  
  9.     Console.WriteLine("MethodOverloading with decimal,out-int Parameters");  
  10. }  
  12. static void MethodOverloadingOut(decimal d, ref int a)  
  13. {  
  14.     a = 10;  
  15.     Console.WriteLine("MethodOverloading with decimal,ref-int Parameters");  
  16. }  
We will get compiler error as,
'Program' cannot define an overloaded method that differs only on parameter modifiers 'ref' and 'out'
 And for the reason, we need to examine the MSIL for this code segment
All About Method Overloading In C#
It is evident from here that Ref and Out are converted to the same MSIL code and hence compiler couldn’t decide what to call and throws an error.
P.S. – I had to rename the method name so that code gets compiled and I can see the MSIL.

Inheritance Scenario for Method Overloading

To get the insight of this, let us see this scenario,
  1. public class BaseClass  
  2. {  
  3.     public void MethodOverloading(string str)  
  4.     {  
  5.         Console.WriteLine("From Base Class.");  
  6.     }  
  7.     public void MethodOverloading2(Object str)  
  8.     {  
  9.         Console.WriteLine("From Base Class.");  
  10.     }  
  12.     public virtual void MethodOverride(string s)  
  13.     {  
  14.         Console.WriteLine("From Base class");  
  15.     }  
  16. }  
  18. class DerivedClass : BaseClass  
  19. {  
  20.     public  void MethodOverloading(object obj)  
  21.     {  
  22.         Console.WriteLine("From Derived Class.");  
  23.     }  
  24.     public void MethodOverloading2(string str)  
  25.     {  
  26.         Console.WriteLine("From Derived Class.");  
  27.     }  
  28.     public override void MethodOverride(string str)  
  29.     {  
  30.         Console.WriteLine("From Derived class -- Overridden Method");  
  31.     }  
  32. }  
and my caller program looks like:
  1. //Scenario # 1  
  2. DerivedClass dc = new DerivedClass();  
  3. dc.MethodOverloading("ATUL");  
  4. dc.MethodOverloading2("ATUL");  
  6. //Scenario # 2  
  7. BaseClass bc = new BaseClass();  
  8. bc.MethodOverloading("ATUL");  
  9. bc.MethodOverloading2("ATUL");  
  11. //Scenario # 3  
  12. BaseClass bcdc = new DerivedClass();  
  13. bcdc.MethodOverloading("Atul");  
  14. bcdc.MethodOverloading2("Atul");  
Now let us examine them one by one,
In Scenario 1, Ii will call the methods from Derived Class, irrespective of the fact that it needs implicit conversion or not. Compiler will see and find it, do the implicit conversion in Derived class and it's DONE!!
In Scenario 2, it will call the methods from Base Class, irrespective of conversion.
In Scenario 3, It will again call from Base class.
There is one very important observation here to talk about,
In the call (Scenario 1) - The compiler doesn't even call the Overridden method, despite tha fact that it has the full match on type with signature. Rather it goes to call the method where it had to convert the string to object.
With this we can infer the following outcomes,
  • Overloading will be supported in normal methods only.
  • For virtual and override, the method signature needs to be exactly the same, else it will be a compiler error. So no Method Overloading is possible in this case.
  • Try to keep the overloading at a class level only, NOT across Inheritance boundaries as it may go to any level.
  • Even if Method overloading is available across the inheritance limits, it will call the method from the type declared, as we saw in the above all 3 scenarios.
With this, I hope you got to learn something new. Comment below for any suggestions or feedback. You can experiment with the code here and explore more scenarios.
The article was initially published here on taagung and I keep updating, when needed.