Practical examples of C# methods and function overloading examples
Let’s start with some concrete examples of C# methods before we even talk about function overloading. These are the kind of methods you actually see in production code.
Example 1: A simple utility method
public static class MathUtils
{
public static int Clamp(int value, int min, int max)
{
if (value < min) return min;
if (value > max) return max;
return value;
}
}
// Usage
int volume = MathUtils.Clamp(userVolume, 0, 100);
This is a classic example of a C# method: a named block of code with parameters and a return value. It does one job, has a clear signature, and is easy to test.
Example 2: Instance method on a domain object
public class Invoice
{
public decimal Subtotal { get; set; }
public decimal TaxRate { get; set; } // 0.07 for 7%
public decimal CalculateTotal()
{
return Subtotal + (Subtotal * TaxRate);
}
}
// Usage
var invoice = new Invoice { Subtotal = 120m, TaxRate = 0.07m };
var total = invoice.CalculateTotal();
This example of a C# method lives on an object and uses its state. You’ll see this style all over business code: methods that read properties and expose a focused behavior.
Example 3: Async method calling a web API
In modern .NET 6–8 apps, async methods are everywhere.
public class WeatherClient
{
private readonly HttpClient _httpClient;
public WeatherClient(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetForecastJsonAsync(string city)
{
var response = await _httpClient.GetAsync($"/forecast?city={city}");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
This is another real example of a C# method: asynchronous, I/O‑bound, and built around Task. You’ll see similar patterns in official .NET samples on learn.microsoft.com.
Function overloading in C#: examples that actually help
Now let’s move into the core topic: examples of C# methods and function overloading examples that make your API nicer to use instead of confusing.
Function overloading in C# means you can define multiple methods with the same name but different parameter lists. The compiler picks the best match based on the arguments you pass.
Example 4: Overloaded logging methods
Here’s a very common example of C# methods and function overloading examples used in logging.
public static class Logger
{
public static void Log(string message)
{
Console.WriteLine($"[INFO] {message}");
}
public static void Log(string message, Exception ex)
{
Console.WriteLine($"[ERROR] {message}\n{ex}");
}
public static void Log(string message, LogLevel level)
{
Console.WriteLine($"[{level}] {message}");
}
}
public enum LogLevel
{
Info,
Warning,
Error
}
// Usage
Logger.Log("Application started");
Logger.Log("Failed to save file", new IOException("Disk full"));
Logger.Log("Low disk space", LogLevel.Warning);
Same method name, different intent. These examples include overloads that accept an exception or a severity level, which is exactly what you want when logging from different places in your codebase.
Example 5: Overloading for different numeric types
Sometimes you want the same logical operation for different numeric types without forcing callers to cast.
public static class DistanceConverter
{
public static double MilesToKilometers(int miles)
{
return miles * 1.60934;
}
public static double MilesToKilometers(double miles)
{
return miles * 1.60934;
}
}
// Usage
double fromInt = DistanceConverter.MilesToKilometers(10); // int
double fromDouble = DistanceConverter.MilesToKilometers(10.5); // double
Here the examples of C# methods and function overloading examples keep the API name the same (MilesToKilometers) while letting callers use either int or double. The overloads are predictable, and the behavior is identical.
Cleaner APIs with optional parameters vs. overloading
Overloading is powerful, but in modern C# you also have optional parameters. You’ll often see both patterns in 2024–2025 codebases, especially in libraries that evolved over time.
Example 6: Overloaded method vs. optional parameter
public class EmailSender
{
// Older style: two overloads
public void Send(string to, string subject, string body)
{
Send(to, subject, body, isHtml: false);
}
public void Send(string to, string subject, string body, bool isHtml)
{
// send email here
}
}
Compare that with an optional parameter:
public class EmailSender
{
public void Send(string to, string subject, string body, bool isHtml = false)
{
// send email here
}
}
Both are valid examples of C# methods and function overloading examples in spirit, but only the first one literally uses overloads. In new code, many teams prefer the optional-parameter style for clarity, unless they need multiple very different signatures.
Microsoft’s own guidelines for .NET API design (see the .NET API design docs on learn.microsoft.com) lean toward clarity: don’t add overloads just because you can.
Real examples of C# methods and function overloading examples in .NET APIs
You don’t have to look far to find real examples. The .NET Base Class Library is full of C# methods and function overloading examples that show how the platform designers think about API ergonomics.
Example 7: Console.WriteLine overloads
Console.WriteLine is a classic example of C# methods and function overloading examples that developers use from day one.
Console.WriteLine("Hello");
Console.WriteLine(42);
Console.WriteLine(3.14);
Console.WriteLine(true);
Console.WriteLine("Name: {0}, Age: {1}", "Alex", 30);
Under the hood, there are many overloads:
public static void WriteLine(string? value);
public static void WriteLine(int value);
public static void WriteLine(double value);
public static void WriteLine(bool value);
public static void WriteLine(string format, params object?[] args);
These examples include type‑specific overloads and a params‑based overload for formatted strings. This is one of the best examples of overloading used to make a common operation extremely convenient.
Example 8: string.IndexOf overloads
Another set of real examples lives in string methods.
string text = "hello world";
int index1 = text.IndexOf('o');
int index2 = text.IndexOf("world");
int index3 = text.IndexOf("o", startIndex: 5);
int index4 = text.IndexOf("HELLO", StringComparison.OrdinalIgnoreCase);
Signatures look like this (simplified):
public int IndexOf(char value);
public int IndexOf(string value);
public int IndexOf(string value, int startIndex);
public int IndexOf(string value, StringComparison comparisonType);
Same method name, different parameters. These examples of C# methods and function overloading examples show how overloads can gradually add more control (like starting position and comparison rules) without changing the basic idea of the method.
Modern C# patterns: extension methods and generic overloads
With C# 12 and .NET 8, you’ll often see extension methods and generics used together. These give you more expressive examples of C# methods and function overloading examples without cluttering your core types.
Example 9: Extension methods with overloads for collections
public static class CollectionExtensions
{
public static bool IsNullOrEmpty<T>(this IEnumerable<T>? source)
{
return source == null || !source.Any();
}
public static bool IsNullOrEmpty<T>(this IReadOnlyCollection<T>? source)
{
return source == null || source.Count == 0;
}
}
// Usage
List<int>? list = null;
bool empty1 = list.IsNullOrEmpty();
IReadOnlyCollection<int> readOnly = new List<int> { 1, 2, 3 };
bool empty2 = readOnly.IsNullOrEmpty();
These overloads share the same method name but target different collection interfaces. That gives you slightly more efficient behavior for IReadOnlyCollection<T> while keeping a clean, discoverable API.
Example 10: Generic overloads with constraints
public static class JsonHelpers
{
public static string Serialize(object value)
{
return System.Text.Json.JsonSerializer.Serialize(value);
}
public static string Serialize<T>(T value) where T : class
{
return System.Text.Json.JsonSerializer.Serialize(value);
}
}
// Usage
string json1 = JsonHelpers.Serialize(new { Name = "Alex", Age = 30 });
string json2 = JsonHelpers.Serialize<Person>(new Person { Name = "Sam" });
These examples of C# methods and function overloading examples show a non‑generic overload and a generic overload side by side. Callers can let type inference do the work, or they can be explicit when they care about the type parameter.
When overloading goes wrong (and how to avoid it)
Not every example of C# methods and function overloading examples is a success story. There are patterns that look clever but hurt readability.
Ambiguous overloads
public void Save(string data) { /* ... */ }
public void Save(object data) { /* ... */ }
// Usage
Save(null); // Which one should this call?
This kind of overloading creates ambiguity. The compiler may complain, or worse, pick an overload you didn’t intend. In code review, this is the sort of thing that gets flagged fast.
Overloads that change behavior too much
public decimal CalculateDiscount(decimal price) { /* flat discount */ }
public decimal CalculateDiscount(decimal price, string couponCode) { /* huge discount */ }
Same name, wildly different semantics. That’s confusing. Better naming beats clever overloading here—maybe CalculateFlatDiscount vs. CalculateCouponDiscount.
The healthiest real examples of C# methods and function overloading examples keep the behavior conceptually the same while adjusting parameters or minor details.
2024–2025 trends: how teams are actually using methods and overloads
Looking at modern .NET 8 codebases, a few patterns keep showing up:
- More async methods: Synchronous I/O methods are being phased out or wrapped in async versions. That means more
GetAsync,SaveAsync, andProcessAsyncmethods, sometimes overloaded with cancellation tokens. - Fewer “kitchen sink” overloads: Libraries are trimming long chains of overloads in favor of simpler signatures with options objects.
- More extension methods: Especially in web APIs (ASP.NET Core), extension methods provide fluent configuration while keeping startup code readable.
Example 11: Async overload with cancellation support
public interface IReportService
{
Task<byte[]> GenerateReportAsync(Guid reportId);
Task<byte[]> GenerateReportAsync(Guid reportId, CancellationToken cancellationToken);
}
These are modern examples of C# methods and function overloading examples that respect cancellation in cloud and microservice environments, where timeouts and graceful shutdowns matter.
If you want to see how large, long‑lived software systems evolve their APIs over time, it’s worth reading about software longevity and maintainability from academic and industry sources. For example, the National Institute of Standards and Technology (NIST) publishes software engineering research at nist.gov.
FAQ: short answers with practical examples
What are some real examples of C# methods I can copy into my project?
Good starting points include:
- A
Clamputility method for numeric ranges - A
CalculateTotalmethod on anInvoiceclass - Async wrapper methods around
HttpClientcalls - Logging helpers like
Log(string message, Exception ex)
These examples of C# methods and function overloading examples are simple, testable, and show up in real production code.
Can you give an example of function overloading that improves readability?
Console.WriteLine is probably the best example of function overloading that improves readability. You can pass strings, numbers, booleans, and formatted values without thinking about which method to call. The overloads match what developers intuitively expect.
When should I avoid creating more overloads?
Avoid adding overloads when:
- The behavior changes so much that a different name would be clearer.
- The overloads create ambiguous calls (for example,
stringvs.objectwithnull). - You’re adding parameters that really belong in a small options object.
In those cases, better naming and simpler signatures beat adding yet another example of C# methods and function overloading examples to your API surface.
Are async and sync versions of a method considered overloading?
Yes. If they share the same name and differ only in parameters or return type (Task<T> vs. T), they’re overloads. Many libraries now expose only async methods, so you’ll see fewer sync/async overload pairs in fresh APIs.
Where can I learn more about designing method APIs in C#?
The best resource is Microsoft’s official .NET documentation on API design at learn.microsoft.com. For a broader software‑engineering perspective, you can also look at:
- General software design guidance from NIST at nist.gov
- Programming and computer‑science course material from universities such as Harvard’s CS50 which covers method design and abstraction in depth.
Use these references as a sanity check whenever you’re about to add yet another overload. If your examples of C# methods and function overloading examples still look clean next to the .NET library patterns, you’re probably on the right track.
Related Topics
Practical examples of polymorphism in C++: function overloading
Best examples of dynamic memory allocation in C++: new and delete
Practical examples of C# variable declaration and initialization examples
Modern examples of C++ operator overloading: custom operators examples that actually matter
Best examples of C# conditional statements: examples & explanations
Real‑world examples of C# exception handling: 3 practical patterns every developer should know
Explore More C++ Code Snippets
Discover more examples and insights in this category.
View All C++ Code Snippets