C# Method Overloading
Introduction
Method overloading is a feature in C# that allows you to define multiple methods with the same name but with different parameters. This powerful concept is part of polymorphism in object-oriented programming and enables you to provide different implementations of a method depending on the input parameters.
When you overload methods, you create multiple methods that share the same name but differ in:
- Number of parameters
- Type of parameters
- Order of parameters
The compiler determines which method to call based on the arguments you provide when calling the method.
Why Use Method Overloading?
Method overloading provides several benefits:
- Improved readability: Methods that perform similar operations can share the same name
- Cleaner code: Avoids creating multiple methods like
AddInt()
,AddDouble()
, etc. - Intuitive API design: Makes your code more natural to use
- Flexibility: Allows handling different types of inputs with a single method name
Basic Method Overloading
Let's start with a simple example of method overloading:
using System;
class Calculator
{
// Method with two integer parameters
public int Add(int a, int b)
{
return a + b;
}
// Method with three integer parameters
public int Add(int a, int b, int c)
{
return a + b + c;
}
// Method with two double parameters
public double Add(double a, double b)
{
return a + b;
}
}
class Program
{
static void Main()
{
Calculator calc = new Calculator();
// Call the first Add method
int sum1 = calc.Add(5, 10);
Console.WriteLine($"Sum of two integers: {sum1}");
// Call the second Add method
int sum2 = calc.Add(5, 10, 15);
Console.WriteLine($"Sum of three integers: {sum2}");
// Call the third Add method
double sum3 = calc.Add(5.5, 10.5);
Console.WriteLine($"Sum of two doubles: {sum3}");
}
}
Output:
Sum of two integers: 15
Sum of three integers: 30
Sum of two doubles: 16
In this example, the Add
method is overloaded three times:
- First version accepts two integers
- Second version accepts three integers
- Third version accepts two doubles
The compiler automatically chooses the correct method based on the arguments provided when the method is called.
Rules for Method Overloading
To successfully overload methods in C#, you must follow these rules:
- Same method name: All overloaded methods must share the same name
- Different parameter lists: Each overloaded method must have a unique parameter list
- Return type doesn't matter: C# cannot differentiate overloaded methods based solely on return type
- Parameter modifiers matter: Using
ref
,out
, orparams
creates different method signatures
Example of Invalid Overloading
This example shows methods that cannot be overloaded:
// INVALID: Methods differ only by return type
int Calculate(int a, int b) { return a + b; }
double Calculate(int a, int b) { return a + b; } // Compiler error!
// VALID: Methods have different parameter types
int Calculate(int a, int b) { return a + b; }
double Calculate(double a, double b) { return a + b; }
Method Overloading with Optional Parameters
C# allows you to combine method overloading with optional parameters:
using System;
class MessageService
{
public void SendMessage(string message)
{
Console.WriteLine($"Sending message: {message}");
}
public void SendMessage(string message, string recipient)
{
Console.WriteLine($"Sending '{message}' to: {recipient}");
}
public void SendMessage(string message, string recipient, bool highPriority = false)
{
string priority = highPriority ? "HIGH PRIORITY" : "normal priority";
Console.WriteLine($"Sending '{message}' to: {recipient} with {priority}");
}
}
class Program
{
static void Main()
{
MessageService messenger = new MessageService();
messenger.SendMessage("Hello World");
messenger.SendMessage("Meeting reminder", "[email protected]");
messenger.SendMessage("Urgent issue", "[email protected]", true);
}
}
Output:
Sending message: Hello World
Sending 'Meeting reminder' to: [email protected]
Sending 'Urgent issue' to: [email protected] with HIGH PRIORITY
Using Method Overloading with Different Parameter Types
Here's an example showing overloaded methods that handle different parameter types:
using System;
class DataProcessor
{
public void Process(int number)
{
Console.WriteLine($"Processing integer: {number}");
}
public void Process(string text)
{
Console.WriteLine($"Processing string: {text}");
}
public void Process(DateTime date)
{
Console.WriteLine($"Processing date: {date.ToShortDateString()}");
}
public void Process(int[] numbers)
{
Console.WriteLine($"Processing {numbers.Length} numbers");
foreach (var num in numbers)
{
Console.Write($"{num} ");
}
Console.WriteLine();
}
}
class Program
{
static void Main()
{
DataProcessor processor = new DataProcessor();
processor.Process(42);
processor.Process("Hello C#");
processor.Process(DateTime.Now);
processor.Process(new int[] { 1, 2, 3, 4, 5 });
}
}
Output:
Processing integer: 42
Processing string: Hello C#
Processing date: 5/15/2023
Processing 5 numbers
1 2 3 4 5
Real-World Application: Formatting Text
Let's look at a more practical example of method overloading for a text formatting utility:
using System;
class TextFormatter
{
// Format just text
public string Format(string text)
{
return text.Trim();
}
// Format with case transformation
public string Format(string text, bool upperCase)
{
string trimmed = text.Trim();
return upperCase ? trimmed.ToUpper() : trimmed.ToLower();
}
// Format with truncation
public string Format(string text, int maxLength)
{
if (text.Length <= maxLength)
return text.Trim();
return text.Trim().Substring(0, maxLength) + "...";
}
// Format with truncation and ellipsis option
public string Format(string text, int maxLength, bool addEllipsis)
{
if (text.Length <= maxLength)
return text.Trim();
string trimmed = text.Trim().Substring(0, maxLength);
return addEllipsis ? trimmed + "..." : trimmed;
}
}
class Program
{
static void Main()
{
TextFormatter formatter = new TextFormatter();
string sampleText = " This is a sample text for demonstration purposes ";
Console.WriteLine($"Original: '{sampleText}'");
Console.WriteLine($"Trimmed: '{formatter.Format(sampleText)}'");
Console.WriteLine($"Uppercase: '{formatter.Format(sampleText, true)}'");
Console.WriteLine($"Truncated to 10 chars: '{formatter.Format(sampleText, 10)}'");
Console.WriteLine($"Truncated to 10 chars without ellipsis: '{formatter.Format(sampleText, 10, false)}'");
}
}
Output:
Original: ' This is a sample text for demonstration purposes '
Trimmed: 'This is a sample text for demonstration purposes'
Uppercase: 'THIS IS A SAMPLE TEXT FOR DEMONSTRATION PURPOSES'
Truncated to 10 chars: 'This is a ...'
Truncated to 10 chars without ellipsis: 'This is a '
Resolving Method Overloading Ambiguity
Sometimes method overloading can lead to ambiguous method calls. The compiler will report an error if it cannot determine which overloaded method to call.
using System;
class Ambiguity
{
// Method 1
public void Display(int num, double value)
{
Console.WriteLine($"Method 1: {num}, {value}");
}
// Method 2
public void Display(double value, int num)
{
Console.WriteLine($"Method 2: {value}, {num}");
}
}
class Program
{
static void Main()
{
Ambiguity example = new Ambiguity();
// These calls are clear
example.Display(10, 20.5); // Calls Method 1
example.Display(20.5, 10); // Calls Method 2
// This call would be ambiguous
// example.Display(10, 10); // Compiler error: Ambiguous call
// Resolve ambiguity with explicit casting
example.Display(10, (double)10); // Calls Method 1
example.Display((double)10, 10); // Calls Method 2
}
}
Method Overloading vs. Optional Parameters
Method overloading and optional parameters serve similar purposes but have different use cases:
using System;
class OverloadingVsOptional
{
// Using overloaded methods
public void Configure(string name)
{
Console.WriteLine($"Name: {name}, Using defaults for other settings");
}
public void Configure(string name, int timeout)
{
Console.WriteLine($"Name: {name}, Timeout: {timeout}ms, Using defaults for other settings");
}
public void Configure(string name, int timeout, bool enableLogging)
{
Console.WriteLine($"Name: {name}, Timeout: {timeout}ms, Logging enabled: {enableLogging}");
}
// Using optional parameters
public void Setup(string name, int timeout = 1000, bool enableLogging = false)
{
Console.WriteLine($"Setup - Name: {name}, Timeout: {timeout}ms, Logging enabled: {enableLogging}");
}
}
class Program
{
static void Main()
{
OverloadingVsOptional example = new OverloadingVsOptional();
// Using overloaded methods
example.Configure("Service1");
example.Configure("Service2", 2000);
example.Configure("Service3", 3000, true);
// Using optional parameters
example.Setup("Service4"); // Using defaults
example.Setup("Service5", 5000); // Specifying timeout
example.Setup("Service6", 6000, true); // Specifying all parameters
example.Setup("Service7", enableLogging: true); // Named parameter, skipping timeout
}
}
Output:
Name: Service1, Using defaults for other settings
Name: Service2, Timeout: 2000ms, Using defaults for other settings
Name: Service3, Timeout: 3000ms, Logging enabled: True
Setup - Name: Service4, Timeout: 1000ms, Logging enabled: False
Setup - Name: Service5, Timeout: 5000ms, Logging enabled: False
Setup - Name: Service6, Timeout: 6000ms, Logging enabled: True
Setup - Name: Service7, Timeout: 1000ms, Logging enabled: True
Summary
Method overloading in C# allows you to define multiple methods with the same name but different parameter lists. This feature enhances code readability, creates more intuitive APIs, and makes your code more flexible.
Key points to remember:
- Methods can be overloaded based on number, type, and order of parameters
- Return type alone is not enough to distinguish overloaded methods
- Method overloading is resolved at compile time, not runtime
- Parameter modifiers like
ref
andout
affect the method signature - Consider using optional parameters as an alternative in some cases
Exercises
- Create a class
MathHelper
with overloaded methods to calculate the area of different shapes (circle, rectangle, and triangle). - Implement a
StringUtils
class with overloadedReverse()
methods that can reverse a string, an array of strings, or characters in a string within a specified range. - Design a
Logger
class with overloadedLog()
methods that handle different severity levels and message formats. - Create a
Converter
class with methods to convert between different units (e.g., miles to kilometers, Celsius to Fahrenheit) using method overloading.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)