Generic Methods

Vaibhav • September 11, 2025

In the last article, we explored how generic classes allow us to build reusable and type-safe data structures. But generics aren’t limited to classes. You can also write generic methods-methods that work across many types without duplicating logic. This is especially useful when the method’s behavior is independent of the specific type it operates on.

What Is a Generic Method?

A generic method is a method that defines its own type parameter. This type parameter is scoped to the method itself and allows the method to operate on different types while maintaining type safety. You declare it using angle brackets <T> before the parameter list.

public static T Echo<T>(T input)
{
    return input;
}

In this example, Echo is a generic method. It accepts a value of any type and returns it. The compiler replaces T with the actual type when the method is called.

int result = Echo(42);           // T is int
string word = Echo("hello");     // T is string

The method works for both integers and strings without needing overloads or casting.

Generic methods can exist inside generic or non-generic classes. Their type parameters are independent of the class’s type parameters.

Why Use Generic Methods?

Generic methods are ideal when the logic of a method is the same across types. They help you:

  • Write reusable logic without duplicating code for each type.
  • Maintain type safety and avoid runtime errors.
  • Improve performance by avoiding boxing/unboxing.

Consider a method that swaps two values. You could write separate methods for int, string, etc., or use a generic method:

public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

This method works for any type and ensures that the values are swapped safely.

Generic Methods in Non-Generic Classes

You don’t need a generic class to use generic methods. You can define them inside regular classes:

public class Utility
{
    public static void Print<T>(T item)
    {
        Console.WriteLine(item);
    }
}

This method prints any type of value. You can call it like this:

Utility.Print(123);       // Output: 123
Utility.Print("Hello");   // Output: Hello

The compiler infers the type of T from the argument.

Type Inference in Generic Methods

One of the most convenient features of generic methods is type inference. In most cases, you don’t need to specify the type parameter explicitly-the compiler figures it out from the arguments.

var result = Echo(3.14); // T is double

However, if the compiler cannot infer the type, you can specify it manually:

var result = Echo<decimal>(3.14m);

This is useful when the method accepts parameters of different types or when you want to enforce a specific type.

Type inference works even with complex types like List<T> or Dictionary<K,V>. The compiler uses the argument’s type to deduce T.

Generic Methods with Multiple Type Parameters

You can define methods with more than one type parameter. This is useful when the method operates on multiple types:

public static void DisplayPair<T1, T2>(T1 first, T2 second)
{
    Console.WriteLine($"First: {first}, Second: {second}");
}

You can call this method with any combination of types:

DisplayPair(1, "One");         // T1 is int, T2 is string
DisplayPair("X", 3.14);        // T1 is string, T2 is double

The compiler infers both type parameters from the arguments.

Constraints in Generic Methods

Sometimes you want to restrict the types that can be used with a generic method. You can use constraints to enforce rules on the type parameters:

public static void Save<T>(T item) where T : IStorable
{
    item.Store();
}

This method only works with types that implement the IStorable interface. If you try to use it with a type that doesn’t, the compiler will show an error.

Constraints are especially useful when you want to call methods or access properties defined in an interface or base class.

Generic Methods and Delegates

You can use generic methods with delegates and lambda expressions. This is common in LINQ and functional programming:

public static T Max<T>(List<T> items, Func<T, int> selector)
{
    return items.OrderByDescending(selector).First();
}

This method finds the item with the highest score based on a selector function. You can use it like this:

var people = new List<Person> { ... };
var topPerson = Max(people, p => p.Score);

The method works for any type as long as you provide a function that maps it to an integer.

Common Pitfalls with Generic Methods

While generic methods are powerful, there are a few things to watch out for:

  • Don’t overuse generics-only use them when type flexibility is needed.
  • Be careful with constraints-missing constraints can lead to compile-time errors.
  • Avoid using object when generics are available-it defeats the purpose of type safety.

Use generic methods to encapsulate reusable logic that works across types. Keep them focused and well-documented, and prefer type inference for cleaner code.

Real-World Examples

Generic methods are everywhere in .NET. Here are a few examples:

  • Enumerable.Select<TSource, TResult> - transforms a sequence.
  • Enumerable.Where<TSource> - filters a sequence.
  • Comparer<T>.Default.Compare - compares two values.

These methods are used in LINQ, collections, and sorting algorithms. They demonstrate how generics make APIs flexible and powerful.

Summary

Generic methods let you write reusable, type-safe logic that works across many types. They’re ideal for utility functions, algorithms, and APIs where the behavior is independent of the specific type. You’ve learned how to define generic methods, use type inference, apply constraints, and avoid common pitfalls. In the next article, we’ll explore Generic Constraints-how to restrict type parameters to enforce design rules and enable specific operations.