CSharpStory_Operations.html
copyright © James Fawcett
Revised: 04/26/2026
4.0 Prologue
This chapter covers the mechanisms C# provides for expressing computation: methods in all
their forms, function-typed delegates, compact lambda expressions, and the powerful LINQ
query model that ties them together.
4.1 Methods
A method belongs to a type. Its signature includes the return type, name, and parameter list.
Parameters are passed by value by default; ref and out pass by
reference; in passes a read-only reference.
int Add(int a, int b) => a + b; // expression-bodied
void Swap(ref int x, ref int y) { // ref parameters
(x, y) = (y, x);
}
bool TryParse(string s, out int result) { // out parameter
return int.TryParse(s, out result);
}
Optional parameters have defaults and must trail required ones.
Named arguments let callers supply values in any order:
Print(message: "hi", color: ConsoleColor.Green);
params lets a method accept a variable number of arguments:
int Sum(params int[] values) => values.Sum();
Local functions (C# 7+) are methods defined inside another method. They
can capture outer variables, have full type inference, and are invisible outside their
enclosing method.
Overloading: multiple methods may share a name if their parameter lists
differ in count or type. Return type alone does not distinguish overloads.
4.2 Operators
C# provides the usual arithmetic, relational, logical, and bitwise operators.
Operator precedence follows mathematical convention; use parentheses when in doubt.
Operator overloading: value types and classes may define custom behavior
for operators such as +, -, ==, and comparison
operators:
readonly struct Vec2 {
public double X { get; init; }
public double Y { get; init; }
public static Vec2 operator+(Vec2 a, Vec2 b) =>
new Vec2 { X = a.X + b.X, Y = a.Y + b.Y };
public static bool operator==(Vec2 a, Vec2 b) =>
a.X == b.X && a.Y == b.Y;
public static bool operator!=(Vec2 a, Vec2 b) => !(a == b);
}
If you overload == you should also override Equals() and
GetHashCode() to keep them consistent.
Conversion operators (implicit / explicit) define
how a type converts to or from another type.
4.3 Delegates
A delegate is a type-safe reference to a method (or group of methods).
The BCL supplies two generic families that cover almost all use cases:
- Action<T1, T2, …> — void return
- Func<T1, T2, …, TResult> — non-void return
- Predicate<T> — equivalent to Func<T, bool>
Func<int, int, int> add = (a, b) => a + b;
Action<string> print = Console.WriteLine;
int result = add(3, 4); // 7
print("hello"); // writes hello
Delegates are multicast: use += to chain multiple methods onto
the same delegate variable. Invoking the delegate calls all chained methods in order.
Events wrap a delegate field and restrict outside callers to only
+= and -= operations — the owning class retains the right to raise
the event:
class Button {
public event Action? Clicked;
public void Click() => Clicked?.Invoke();
}
4.4 Lambdas and Anonymous Methods
A lambda expression is an inline anonymous function. It can be assigned
to a compatible delegate type or passed directly as an argument:
Func<int, bool> isEven = n => n % 2 == 0;
// statement lambda (multiple lines)
Func<int, int> factorial = n => {
int r = 1;
for (int i = 2; i <= n; i++) r *= i;
return r;
};
Lambdas capture variables from the enclosing scope by reference (a
closure). Be careful when capturing loop variables — each iteration shares the same
variable unless you copy it to a local.
Static lambdas (C# 9+, prefix static) are forbidden from
capturing instance state, helping avoid unintended allocations.
4.5 LINQ
Language Integrated Query (LINQ) provides a unified model for querying
any sequence that implements IEnumerable<T>, including arrays, lists,
XML trees, database result sets, and more.
Two equivalent syntaxes — query syntax (SQL-like) and
method syntax (fluent extension methods):
int[] nums = { 5, 3, 8, 1, 9, 2, 6 };
// query syntax
var q1 = from n in nums
where n > 4
orderby n descending
select n * n;
// method syntax (identical result)
var q2 = nums.Where(n => n > 4)
.OrderByDescending(n => n)
.Select(n => n * n);
Key LINQ operators:
- Where — filter by predicate
- Select — transform each element
- SelectMany — flatten nested sequences
- OrderBy / OrderByDescending — sort
- GroupBy — partition into keyed groups
- Join / GroupJoin — correlate two sequences
- Distinct / Union / Intersect / Except — set operations
- First / Last / Single / ElementAt — element access
- Any / All / Count / Sum / Min / Max / Average — aggregation
- ToList / ToArray / ToDictionary — materialize
LINQ queries are lazy: they do not execute until the sequence is
enumerated (e.g., in a foreach, or when calling ToList()).
This enables efficient pipelining and deferred evaluation.
4.6 Extension Methods
An extension method is a static method defined in a static class whose
first parameter is prefixed with this. It is called as if it were an instance
method on the target type:
public static class StringExtensions {
public static bool IsPalindrome(this string s) {
int n = s.Length;
for (int i = 0; i < n / 2; i++)
if (s[i] != s[n - 1 - i]) return false;
return true;
}
}
// usage
bool ok = "racecar".IsPalindrome(); // true
All LINQ operators are extension methods on IEnumerable<T> defined in
System.Linq. Extension methods can be defined for interfaces, sealed classes,
or any type you cannot modify.
4.7 Iterators
A method that contains yield return becomes an iterator.
It returns an IEnumerable<T> and produces values lazily — each call to
the enumerator's MoveNext() resumes execution at the next
yield return:
IEnumerable<int> Fibonacci() {
int a = 0, b = 1;
while (true) {
yield return a;
(a, b) = (b, a + b);
}
}
foreach (int f in Fibonacci().Take(10))
Console.Write(f + " "); // 0 1 1 2 3 5 8 13 21 34
yield break ends the iteration early. Iterators compose naturally with LINQ
operators.
4.8 Epilogue
This chapter covered C# computation: methods in all their forms, operators, delegates and
events, lambdas, LINQ, extension methods, and iterators. The next chapter explores how data
and operations are packaged into classes.
4.9 References
LINQ — Microsoft docs
Delegates — Microsoft docs
Lambda expressions
Extension methods