Methods
C# methods: signatures, parameters, overloads, optional + named args, ref / out / in, and the patterns that age well.
C# — methods
EXAMPLE
// ===== Basic signature =====
public int Add(int a, int b) => a + b;
public static int Sum(IEnumerable<int> xs) => xs.Sum();
// Expression-bodied for one-liners; braces for multi-line.
// ===== Overloads =====
public int Add(int a, int b) => a + b;
public double Add(double a, double b) => a + b;
public int Add(int a, int b, int c) => a + b + c;
// Compiler picks the best match by arg types + count.
// ===== Optional parameters =====
public string Greet(string name, string greeting = "Hello") => $"{greeting}, {name}";
Greet("Alex"); // 'Hello, Alex'
Greet("Alex", "Hi"); // 'Hi, Alex'
// ===== Named arguments =====
SendEmail(to: "a@x.io", subject: "hi", body: "hello", priority: 5);
// Useful for methods with many params or all-optional ones.
// ===== params (variadic) =====
public int Sum(params int[] xs) {
int s = 0; foreach (var x in xs) s += x; return s;
}
Sum(1, 2, 3, 4); // 10
Sum(new[] { 1, 2, 3 }); // 6 (still works)
// ===== ref / out / in =====
public bool TryParse(string s, out int value) {
if (int.TryParse(s, out value)) return true;
value = 0; return false;
}
if (TryParse("42", out var n)) Console.WriteLine(n);
public void Swap(ref int a, ref int b) { (a, b) = (b, a); }
// in: pass by readonly reference (avoids copy of large structs)
public double Distance(in Point p1, in Point p2) { /* ... */ }
// ===== Async =====
public async Task<string> FetchAsync(string url) {
using var http = new HttpClient();
return await http.GetStringAsync(url);
}
// Always return Task / Task<T> / ValueTask for async; never async void (except event handlers).
// ===== Local functions =====
public IEnumerable<int> Doubled(IEnumerable<int> xs) {
return xs.Select(Inner);
int Inner(int n) => n * 2;
}
// ===== Extension methods =====
public static class StringExt {
public static bool IsEmpty(this string? s) => string.IsNullOrEmpty(s);
}
"hello".IsEmpty(); // false (extension methods feel like instance methods)
// ===== Generics =====
public static T First<T>(IReadOnlyList<T> xs) => xs[0];
public static TResult Map<TIn, TResult>(TIn x, Func<TIn, TResult> f) => f(x);
// Constraints:
public static T Max<T>(T a, T b) where T : IComparable<T>
=> a.CompareTo(b) >= 0 ? a : b;
// ===== Patterns to internalise =====
// - Expression-bodied members for one-liners
// - Named args when there are 3+ parameters
// - TryX pattern with bool return + out value
// - async all the way down at I/O boundaries
// - Extension methods for fluent APIs
// ===== Pitfalls =====
// - async void (except event handlers) -> unobservable exceptions
// - Default param values change with re-compile cascading (callers may pick up new defaults)
// - Overuse of out -> hard to read; prefer tuples ($"Try{Name}")
// - Capturing this in delegates -> retain references longer than expected
Why it matters
C# methods are dense in features: overloads, optional + named args, params, ref/out/in, async, generics, extensions. Use expression-bodied for short, named args for clarity, TryX for safe parsing, and async at the IO boundary. The language rewards small, focused methods.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
static int Add(int a, int b) => a + b; static int Add(int a, int b, int c) => a + b + c; // overload Console.WriteLine(Add(2, 3));Try it Yourself »
Exercise
Expression-bodied method.
static int Add(int a, int b)
a + b;
Two characters.
Discussion
Loading…