C#:.NET:Method

.NET Array Dictionary List String 2D Async DataTable Dates DateTime Enum File For Foreach Format IEnumerable If IndexOf Lambda Parse Path Process Property Regex Replace Row Sort Split Static StringBuilder Substring Switch Tuple Window

Overloaded methods improve code clarity. When designing complex programs, code changes and some branches become unnecessary. We add overloaded methods to eliminate complexity and enhance performance.
Example. First, overloaded methods are separate in the compiled program. A method receiving a string parameter is separate from one receiving no parameter or an int. The methods are stored at different locations within the metadata.Int

Note: This programming technique results in method groups with a single identifier—a single method name.

C# program that has overloaded methods

class Program
{
    static void Main()
    {
	MethodA();
	MethodA("");
    }

    static void MethodA()
    {
    }

    static void MethodA(string a)
    {
    }
}
Example 2. Next we look at one situation where you can apply overloaded methods. Here we are not focusing on polymorphism and inheritance, but rather a simpler way of improving code readability and performance. Here's some code that is problematic.
C# program that has no overloaded methods

using System;

class Program
{
    public static void Main()
    {
	ShowString(string.Empty);
	ShowString("Category");
    }

    static void ShowString(string value)
    {
	if (value == string.Empty)
	{
	    Console.WriteLine("Popular");
	}
	else
	{
	    Console.WriteLine(value);
	}
    }
}
In this example, the code writes the word Popular to the screen if the string argument is empty. Otherwise, it writes the category name. But this code is inefficient and confusing. We can entirely avoid the string.Empty argument.string.Empty
Example 3. The code above has an unnecessary branch, but this cannot be optimized out by the compiler in the IL code. The code calls into ShowString, but we know that the string is never empty at that call site.
When optimizing C, I learned that removing branches increases performance. Processors use branch prediction, but this is not ideal. You want your code to go sequentially from beginning to end.
C# program that implements overloaded method

using System;

class Program
{
    public static void Main()
    {
	ShowString();
	ShowString("Category");
    }

    static void ShowString()
    {
	// Send default argument to overload.
	ShowString("Popular");
    }

    static void ShowString(string value)
    {
	// We don't need an if check here, which makes
	// ... calling this method directly faster.
	Console.WriteLine(value);
    }
}
In this example, there is an overload with no parameters, and one with a string parameter. Overloaded methods always have different parameters. Look at what happens when ShowString is called the second time.

Note: There is no if-statement. It goes directly from the call site to the Console.WriteLine part.

Console.WriteLine

And: The processor won't have to do any branch prediction, because there is no branch.


Internals. Here we look into the IL (intermediate language) to see what the overloaded methods become when first compiled. First, let's look inside the ShowString method that has the if-statement.IL
Compiled method that does not use overloading: IL

.method private hidebysig static void  ShowString(string 'value') cil managed
{
  // Code size       31 (0x1f)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldsfld     string [mscorlib]System.String::Empty
  IL_0006:  call       bool [mscorlib]System.String::op_Equality(string,
								 string)
  IL_000b:  brfalse.s  IL_0018
  IL_000d:  ldstr      "Popular"
  IL_0012:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0017:  ret
  IL_0018:  ldarg.0
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001e:  ret
}
The if chain in ShowString uses an op_Equality. None of this is compiled out and it also can't be optimized away during JIT compilation. Therefore, ShowString will always have the branch.JIT

Next: We show how the overloaded methods are called in the second example. The methods are separate.

And: The compiler can easily tell the difference between overloads with different parameters.

Compiled methods that use overloading: IL

.method public hidebysig specialname rtspecialname
	instance void  .ctor() cil managed
{
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  call       void OverloadA::ShowString()
  IL_000b:  ldstr      "Category"
  IL_0010:  call       void OverloadA::ShowString(string)
  IL_0015:  ret
}

.method private hidebysig static void  ShowString() cil managed
{
  // Code size       11 (0xb)
  .maxstack  8
  IL_0000:  ldstr      "Popular"
  IL_0005:  call       void OverloadA::ShowString(string)
  IL_000a:  ret
}
Finally, the ShowString method doesn't need any if-else chain at all. It simply does what it is told, without any checking. Your processor will more easily pipeline these instructions. And the code will be more efficient.If
Summary. It is possible to refactor code to use method overloading. The overloads are easily inferred by the compiler. You can streamline old code that contains unnecessary if-else chains, eliminating run-time inefficiencies.