Generics in C#

Generics in C# allow you to write type-safe and reusable code that can work with different data types without requiring explicit casting or boxing/unboxing. They introduce the concept of type parameters, which act as placeholders for the actual types that will be specified later when the generic type is used.

Why Use Generics?

Defining Generic Classes and Interfaces

You define a generic class or interface by including one or more type parameters within angle brackets <T> after the class or interface name. For example:

public class MyGenericClass<T> {
        private T myField;

        public MyGenericClass(T value) {
            myField = value;
        }

        public T GetValue() {
            return myField;
        }
    }

In this example, T is a type parameter. When you create an instance of `MyGenericClass`, you specify the actual type for T:

MyGenericClass<int> intInstance = new MyGenericClass<int>(10);
    MyGenericClass<string> stringInstance = new MyGenericClass<string>("hello");

Generic Methods

Methods can also be generic. The type parameter is specified in the method signature:

public static T MyGenericMethod<T>(T arg) {
        return arg;
    }

You can call a generic method like this:

int result = MyGenericMethod<int>(5); // Explicitly specifying the type
    string strResult = MyGenericMethod("world"); // Type inference (often preferred)

Constraints

You can constrain the type parameters to specific types or interfaces using the where keyword. This allows you to specify that a type parameter must meet certain requirements. For example:

public class MyConstrainedClass<T> where T : class, IComparable<T> { ... }

This constraint specifies that T must be a reference type (`class`) and must implement the `IComparable<T>` interface.

Summary

Generics are a powerful feature in C# that significantly improves type safety, code reusability, and performance. They are widely used in the .NET framework and are essential for writing modern, robust C# applications.