Generic Algorithms
Vaibhav • September 11, 2025
In the previous article, we explored how reflection allows us to inspect and manipulate generic types at runtime. Now we shift our focus to something more practical and performance-oriented: generic algorithms. These are algorithms written using generics so they can operate on a wide range of types without sacrificing type safety or performance. Whether you're sorting, filtering, searching, or transforming data, generic algorithms help you write reusable logic that adapts to the types you work with.
What Are Generic Algorithms?
A generic algorithm is a method or function that performs a computation or transformation using type parameters.
Instead of hardcoding the type (like int
or string
), you use a generic type parameter
(T
) so the algorithm works for any type that satisfies the required constraints.
public static T Max<T>(List<T> items) where T : IComparable<T>
{
if (items == null || items.Count == 0)
throw new ArgumentException("List cannot be empty");
T max = items[0];
foreach (T item in items)
{
if (item.CompareTo(max) > 0)
max = item;
}
return max;
}
This algorithm finds the maximum value in a list of any type T
, as long as T
implements IComparable<T>
. It works for int
, string
,
DateTime
, or any custom type that supports comparison.
Why Use Generic Algorithms?
Generic algorithms help you:
- Avoid code duplication across types.
- Maintain type safety and avoid casting.
- Improve performance by avoiding boxing/unboxing.
- Write cleaner, more expressive code.
They’re especially useful in libraries, utilities, and frameworks where the logic is independent of the specific type.
Example: Generic Swap Algorithm
Swapping two values is a common operation. Here’s a generic version:
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
This method works for any type-int
, string
, Point
, etc. It uses
ref
parameters to modify the original variables. The logic is simple, but the generic version makes
it reusable across your entire codebase.
Example: Generic Filter Algorithm
Filtering a list based on a condition is another common task. Here’s a generic filter method:
public static List<T> Filter<T>(List<T> items, Func<T, bool> predicate)
{
List<T> result = new List<T>();
foreach (T item in items)
{
if (predicate(item))
result.Add(item);
}
return result;
}
This method takes a list of items and a predicate function, and returns a new list containing only the items that match the condition. It works for any type and any condition.
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evens = Filter(numbers, x => x % 2 == 0);
This example filters out even numbers. You can use the same method to filter strings, dates, or custom objects.
Example: Generic Transform Algorithm
Transforming a list from one type to another is a common pattern. Here’s a generic map method:
public static List<TResult> Map<TSource, TResult>(List<TSource> items, Func<TSource, TResult> selector)
{
List<TResult> result = new List<TResult>();
foreach (TSource item in items)
{
result.Add(selector(item));
}
return result;
}
This method takes a list of source items and a selector function, and returns a new list of transformed results.
It’s the foundation of LINQ’s Select
method.
var names = new List<string> { "Alice", "Bob" };
var lengths = Map(names, name => name.Length);
This example maps names to their lengths. You can use the same method to convert objects, extract fields, or compute derived values.
Example: Generic Search Algorithm
Searching for an item in a list is another common task. Here’s a generic search method:
public static T FindFirst<T>(List<T> items, Func<T, bool> predicate)
{
foreach (T item in items)
{
if (predicate(item))
return item;
}
return default(T);
}
This method returns the first item that matches the condition, or default(T)
if none is found. It
works for any type and any condition.
var words = new List<string> { "cat", "dog", "elephant" };
var longWord = FindFirst(words, w => w.Length > 5);
This example finds the first word longer than five characters. You can use the same method to search numbers, dates, or custom objects.
Example: Generic Sort Algorithm
Sorting a list requires comparison. Here’s a generic sort method using IComparer<T>
:
public static void Sort<T>(List<T> items, IComparer<T> comparer)
{
items.Sort(comparer);
}
This method delegates to the built-in Sort
method but allows you to pass a custom comparer. You can
sort by name, date, score, or any other criteria.
var people = new List<Person> { ... };
Sort(people, new PersonNameComparer());
This example sorts people by name using a custom comparer. You can define your own
IComparer<T>
for any type.
Design Tips for Generic Algorithms
When writing generic algorithms:
- Use constraints to enforce required capabilities (like IComparable<T>
).
- Use Func<T, TResult>
and Predicate<T>
for flexibility.
- Avoid assumptions about the type-let the caller provide logic.
- Return default(T)
when no result is found.
- Keep the algorithm focused and composable.
Write generic algorithms that do one thing well. Keep them small, composable, and testable. Use delegates to inject behavior and constraints to enforce correctness.
Testing Generic Algorithms
Generic algorithms should be tested with multiple types:
- Value types like int
, double
, bool
- Reference types like string
, List<T>
, custom classes
- Nullable types like int?
, DateTime?
- Edge cases like empty lists, null
values, and duplicates
This ensures your algorithm behaves correctly across scenarios and doesn’t rely on type-specific behavior.
Summary
Generic algorithms are reusable, type-safe methods that perform computations across a wide range of types.
You’ve learned how to write generic algorithms for swapping, filtering, mapping, searching, and sorting. You’ve
seen how to use constraints, delegates, and default(T)
to make your algorithms safe and flexible.
You’ve also learned how to test and design them for clarity and performance. In the next article, we’ll wrap up
Chapter 13 with a review and practical exercises to reinforce your understanding of generics and type safety.