কেন 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;