Imagine your architecture firm has a blueprint printer. Sometimes clients give you just a room name. Other times they provide exact dimensions. Occasionally, they want a deluxe custom print with dimensions and a style label. Do you need three different printers? No! You need one printer smart enough to handle all three scenarios.
That's method overloading — defining multiple methods with the same name but different parameter lists. The compiler picks the right version based on the arguments you pass. It's like having one tool that adapts to whatever job you throw at it.
🔑 The Rules of Overloading
For method overloading to work, the overloaded methods must differ in at least one of these ways:
Number of parameters — e.g., Print(string name) vs Print(string name, int width).
Type of parameters — e.g., Print(int id) vs Print(string name).
Order of parameter types — e.g., Print(int a, string b) vs Print(string a, int b).
⚠️ Return type alone does NOT count — you can't overload by just changing the return type.
// Overload 1: Just a name
static void PrintBlueprint(string name)
{
Console.WriteLine($"Blueprint: {name}");
}
// Overload 2: Name + integer dimensions
static void PrintBlueprint(string name, int width, int height)
{
Console.WriteLine($"Blueprint: {name} {width}x{height}");
}
// Overload 3: Name + double dimensions + style
static void PrintBlueprint(string name, double width, double height, string style)
{
Console.WriteLine($"Blueprint: {name} {width}x{height} ({style})");
}
🎯 Overload Resolution — How the Compiler Chooses
When you call an overloaded method, the C# compiler examines the arguments you provide and selects the best matching overload. This is called overload resolution and happens at compile time (not runtime). It's a form of compile-time polymorphism — the same method name behaves differently depending on the input.
Overloading = same name, different parameters, same class. Resolved at compile time.
Overriding = same name, same parameters, different class (inheritance). Resolved at runtime.
We'll explore overriding later when we study inheritance. For now, focus on overloading!
🏗️ Real-World Example: Console.WriteLine
You've been using method overloading all along! Console.WriteLine has 19 overloads — it can accept a string, int, double, bool, object, a format string with arguments, and more. One name, many forms.
Method overloading lets you define multiple methods with the same name but different parameter lists.
The compiler selects the correct overload based on the arguments — this is compile-time polymorphism.
You cannot overload by changing only the return type.
Console.WriteLine is the most famous overloaded method in C#.
Overloading keeps your API clean — one intuitive name for related operations.
📋 Instructions
**The Blueprint Printer**
Build a multi-purpose blueprint printer using method overloading:
1. Define `static void PrintBlueprint(string name)` — prints `Blueprint: Standard {name}`
2. Define `static void PrintBlueprint(string name, int width, int height)` — prints `Blueprint: {name} {width}x{height}`
3. Define `static void PrintBlueprint(string name, double width, double height, string style)` — prints `Blueprint: {name} {width}x{height} ({style})`
4. In `Main`:
- Call `PrintBlueprint("Room")` → should print `Blueprint: Standard Room`
- Call `PrintBlueprint("Room", 5, 3)` → should print `Blueprint: Room 5x3`
- Call `PrintBlueprint("Custom Room", 4.5, 3.2, "Deluxe")` → should print `Blueprint: Custom Room 4.5x3.2 (Deluxe)`
- Print `Overloading is powerful!`
Define three methods all named `PrintBlueprint` but with different parameter lists. The first takes just `string name`, the second takes `string name, int width, int height`, and the third takes `string name, double width, double height, string style`. The compiler matches the call to the right overload based on the arguments you pass.