Functions & Methods in C#
Define methods with parameters, return types, optional/default parameters, named arguments, params arrays, local functions, expression-bodied members, and higher-order methods.
Method Basics & Execution Flow
1. Creating and Calling a Method
A method is a reusable block of code with a name. Call it by writing its name followed by `()`.
2. Method Execution Flow
When a method is called, execution jumps into it and returns to the caller when done.
3. Return Values
A method can return a value using the `return` keyword. Declare the return type instead of `void`.
Parameters & Arguments
1. Basic Parameters
Parameters are variables declared in the method signature. Arguments are the values passed when calling.
2. Optional / Default Parameters
Give a parameter a default value — callers can omit it.
3. Named Arguments
Pass arguments by name — allows any order and improves readability.
Unlimited Parameters (params)
1. params Array
`params` allows a method to accept any number of arguments of the same type.
2. Passing an Array to a params Method
An existing array can be passed directly to a `params` parameter.
Method Forms
1. Expression-Bodied Methods (=>)
Short one-liner methods can use `=>` instead of a full `{}` body.
2. Local Functions
A function defined inside another function — only visible within the enclosing method.
3. Anonymous Functions & Lambdas
Lambdas are inline anonymous functions using `=>`. Commonly used with delegates and LINQ.
Method Overloading
1. Basic Overloading
Same method name, different parameter types or counts — C# picks the right one at compile time.
Pass-by-Value vs Pass-by-Reference
1. Value Types Are Copied
Primitives are passed by value — the method gets a copy, original is unchanged.
2. ref and out — Pass by Reference
`ref` passes a reference to the original variable. `out` is like `ref` but the method must assign it.
Higher-Order Methods (Custom Implementation)
1. What is a Higher-Order Method?
A method that accepts another method (delegate/lambda) as a parameter or returns one.
2. Creating map() from Scratch
Build a `Map` method that transforms every element using a function.
3. Creating filter() from Scratch
Build a `Filter` method that keeps only elements matching a predicate.
4. Creating reduce() from Scratch
Build a `Reduce` method that accumulates all elements into a single value.
5. Creating forEach() from Scratch
Build a `ForEach` method that calls an action on each element.
6. Creating find() from Scratch
Build a `Find` method that returns the first matching element or a default.
7. Creating findIndex() from Scratch
Build a `FindIndex` method that returns the index of the first matching element.
8. Creating some() & every() from Scratch
`Some` checks if any element matches. `Every` checks if all elements match.
9. Creating group() from Scratch
Build a `Group` method that groups elements into a `Dictionary<K, List<T>>` by a key.
10. Creating a Custom Higher-Order Method
Build a `Transform` method that applies a transformation and filters in one pass.
Closures & State
What is a Closure?
A function that captures variables from its enclosing scope.
Stateful Closure — Counter
Maintain private state across calls using a captured variable.
Closure as a Configurable Function
Bake a parameter into a returned lambda (partial application).
Closure in Loops — Common Pitfall
All lambdas share the same loop variable — copy it to fix.
Closure for Memoization
Cache expensive results in a privately captured dictionary.