Generics in C#

লেসন ১১ / ৫০

কেন Generic?

একই code একাধিক type-এর জন্য reuse — type safety সহ।

// ❌ Without generic — boxing/unboxing
class IntList {
    private object[] items;
    public void Add(int x) { ... }
}
class StringList {
    private object[] items;
    public void Add(string x) { ... }
}

// ✅ Generic — একটি class সবার জন্য
class MyList<T> {
    private T[] items;
    public void Add(T x) { ... }
    public T Get(int i) => items[i];
}

Generic Class

public class Repository<T> where T : class {
    private List<T> _items = new();

    public void Add(T item) => _items.Add(item);
    public T GetById(Func<T, bool> predicate) => _items.FirstOrDefault(predicate);
    public IEnumerable<T> GetAll() => _items;
}

// ব্যবহার
var userRepo = new Repository<User>();
var productRepo = new Repository<Product>();

Generic Method

public T Max<T>(T a, T b) where T : IComparable<T> {
    return a.CompareTo(b) > 0 ? a : b;
}

int m1 = Max(5, 10);
string m2 = Max("apple", "banana");

// Multiple type parameters
public Dictionary<TKey, TValue> ToDict<TKey, TValue>(
    IEnumerable<TValue> items, Func<TValue, TKey> keySelector
) => items.ToDictionary(keySelector);

Constraints

where T : class             // reference type
where T : struct            // value type
where T : new()             // parameterless constructor
where T : BaseClass         // BaseClass বা derived
where T : IInterface        // interface implement
where T : unmanaged         // unmanaged type
where T : notnull           // non-nullable

// Multiple
public T Create<T>() where T : class, IRepository, new() {
    return new T();
}

Built-in Generic Types

List<T>
Dictionary<TKey, TValue>
HashSet<T>
Queue<T> / Stack<T>
IEnumerable<T>
Task<T>
Func<T, TResult>
Action<T>
Nullable<T>     // int? = Nullable<int>

Covariance/Contravariance

// out — covariant (return only)
IEnumerable<Animal> animals = new List<Dog>();

// in — contravariant (input only)
Action<Dog> dogAction = (Action<Animal>)animalAction;