Generic

Câu hỏi phỏng vấn Generic

40+ câu hỏi Generic — C# và TypeScript — cho fresher/junior backend/fullstack.

A. Cơ bản

1. Generic là gì? Giải quyết vấn đề gì?

Parametric polymorphism — viết code làm việc với nhiều type mà giữ type safety. Lợi ích:

  • Type safety compile-time.
  • Code reuse (không duplicate cho từng type).
  • Performance (C# value type không boxing).
  • Self-documenting.

2. Generic khác Inheritance polymorphism chỗ nào?

  • Inheritance (subtype polymorphism): runtime, qua vtable.
  • Generic (parametric polymorphism): compile-time check, có thể combine với subtype (constraint).

3. Generic function vs Generic class — khác gì?

  • Function: type param chỉ trong scope function. T Identity<T>(T x).
  • Class: type param share toàn class. Box<T> — mọi instance có T cụ thể.

4. Type inference trong generic?

Compiler suy luận type param từ argument. Identity(42)T = int. Khi không inferred được → phải specify thủ công.

5. Generic method trong non-generic class?

Class non-generic vẫn có thể có method generic riêng:

class Cache {
    public void Set<T>(string key, T value) { ... }
}

B. Constraint

6. Constraint là gì?

Hạn chế type parameter T phải thoả điều kiện — implement interface, extend class, có constructor, là value/ref type, v.v.

7. Liệt kê constraint C# phổ biến?

  • where T : class — reference type.
  • where T : struct — value type.
  • where T : new() — có default ctor.
  • where T : IInterface — implement interface.
  • where T : BaseClass — kế thừa.
  • where T : Enum — enum (C# 7.3+).
  • where T : INumber<T> — static interface (C# 11+).
  • where T : U — linked với U.

8. TS constraint với extends ra sao?

function len<T extends { length: number }>(x: T) { return x.length; }
function get<T, K extends keyof T>(o: T, k: K): T[K] { return o[k]; }

9. keyof T trong TS là gì?

Union các key của T dưới dạng string literal type:

keyof { id: number; name: string }   // "id" | "name"

10. T[K] indexed access?

Lấy value type theo key: User["name"] = string. Combine với keyof cho type-safe access.

11. Generic constraint với keyof — vì sao mạnh?

Type-safe property access — compile-time check key tồn tại + return đúng type:

function get<T, K extends keyof T>(obj: T, key: K): T[K]

12. Multi constraint?

C#: where T : class, IDisposable, new(). TS: T extends Iterable<U> & { length: number }.

C. Variance

13. Variance là gì? 3 loại?

Quan hệ subtype giữa generic instantiation:

  • Covariant (out): nếu Dog : Animal thì F<Dog> : F<Animal>. Producer.
  • Contravariant (in): F : F. Consumer.
  • Invariant (default): không quan hệ.

14. Vì sao List<T> không covariant?

Có cả Add(T) (input) và this[i] (output). Nếu covariant → có thể Add Cat vào List<Animal> chứa Dog → crash. Mixed → phải invariant.

15. Vì sao IEnumerable<T> covariant?

T chỉ ở output (return của GetEnumerator/Current). Không Add được. Safe để covariant — IEnumerable<Dog> assignable sang IEnumerable<Animal>.

16. Vì sao IComparer<T> contravariant?

T chỉ ở input của Compare. Comparer so sánh được Animal → cũng so sánh được Dog (Dog là Animal). Đảo chiều.

17. Mnemonic variance?

"out → cùng hướng (covariant), in → ngược hướng (contravariant)". Producer covariant, Consumer contravariant.

18. TS variance — auto hay explicit?

Mặc định auto-inferred từ usage. TS 4.7+ thêm explicit out/in annotation nhưng không bắt buộc.

19. Bivariant function param trong TS?

TS mặc định cho function param bivariant (vừa cov vừa contra) — không strict. Bật strictFunctionTypes: true → chỉ contravariant (đúng lý thuyết).

20. Function variance — return vs param?

  • Return covariant (subtype).
  • Param contravariant (supertype).

(Animal => Dog) assignable sang (Dog => Animal) vì:

  • Return Dog : Animal ✅
  • Param Animal supertype của Dog ✅

D. C# vs TS

21. Reified vs Erased generic?

  • Reified (C#, Java modern): runtime giữ type info. typeof(List<int>) != typeof(List<string>).
  • Erased (TS, Java legacy): generic biến mất sau compile.

22. Khác biệt thực tế reified vs erased?

C# có thể:

  • new T() (với new() constraint).
  • typeof(T) runtime.
  • Reflection introspect generic.
  • Overload theo generic type.

TS không có những thứ trên — phải workaround.

23. Trong TS, tạo instance từ generic type sao?

Nhận constructor làm param:

function create<T>(Ctor: new () => T): T { return new Ctor(); }

24. C# generic không boxing — ý nghĩa?

List<int> lưu int trực tiếp, không wrap thành object trên heap. Compile sinh IL specialized cho mỗi value type → fast. ArrayList thì box mỗi int.

25. Generic + reflection trong C#?

var type = typeof(List<>).MakeGenericType(typeof(string));
var inst = Activator.CreateInstance(type);

Tạo type generic runtime — power lớn cho ORM, DI container.

E. Advanced TS

26. Conditional type là gì?

T extends U ? X : Y — chọn type theo điều kiện. Cơ sở của mọi utility type advanced.

27. Distributive conditional?

Khi T là naked type param + T là union → conditional apply cho từng member:

type ToArr<T> = T extends any ? T[] : never;
type R = ToArr<string | number>;   // string[] | number[]

28. Chống distribute?

Wrap T trong tuple: [T] extends [U] ? ... : ....

29. infer keyword?

Bắt type trong nhánh conditional:

type Return<F> = F extends (...a: any) => infer R ? R : never;

30. Mapped type?

Tạo type mới bằng map qua keys:

type Readonly<T> = { readonly [K in keyof T]: T[K] };
type Partial<T> = { [K in keyof T]?: T[K] };

31. Key remapping (TS 4.1+)?

[K in keyof T as NewKey]:

type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };

32. Template literal type?

String literal có placeholder: `Hello, ${string}!`. Combine với union để sinh permutation.

F. Real-world

33. Implement Repository generic trong C#?

public abstract class Repository<T> where T : class, IEntity, new() {
    protected DbContext _ctx;
    public Repository(DbContext ctx) => _ctx = ctx;
    public Task<T?> GetByIdAsync(int id) => _ctx.Set<T>().FindAsync(id).AsTask();
    public async Task AddAsync(T e) { _ctx.Set<T>().Add(e); await _ctx.SaveChangesAsync(); }
}

34. Implement type-safe API client trong TS?

async function fetchJson<T>(url: string, schema: ZodType<T>): Promise<T> {
    const data = await fetch(url).then(r => r.json());
    return schema.parse(data);     // runtime validate
}

35. Self-referencing generic (CRTP)?

public abstract class Builder<TSelf> where TSelf : Builder<TSelf> {
    public TSelf SetName(string n) { ... return (TSelf)this; }
}
public class UserBuilder : Builder<UserBuilder> {
    public UserBuilder SetEmail(string e) { ... return this; }
}

→ Fluent chain giữ đúng concrete type.

36. Type-safe Object.keys trong TS?

Object.keys trả string[]. Wrap:

function keys<T extends object>(o: T): (keyof T)[] {
    return Object.keys(o) as (keyof T)[];
}

37. Branded type cho ID?

type UserId = number & { __brand: "UserId" };
type OrderId = number & { __brand: "OrderId" };

Chống nhầm UserId với OrderId dù cùng number.

G. Câu trick

38. Generic và default(T) — trả gì?

C#: default(T) = null nếu T ref type, 0 cho int, default struct cho struct. TS: không có cú pháp tương đương — thường khởi null hoặc undefined.

39. where T : class? C# nghĩa là gì?

T là nullable reference type (C# 9+). where T : class thì T là non-null ref. ? cho phép null.

40. Tại sao TS Promise<T> covariant?

T chỉ xuất hiện ở output (.then(value: T)). Producer → covariant. Promise<Dog> assignable sang Promise<Animal>.

41. C# Action<T> vs Func<T> variance?

  • Action<in T>: T input → contravariant.
  • Func<out T>: T return → covariant.
  • Func<in T, out R>: input contra, output cov.

42. Tại sao Array<T> trong TS hoạt động như covariant?

TS không enforce variance trên built-in Array do legacy + bivariant default. Strict mode → coi như covariant nhưng vẫn cho phép push (unsoundness có ý).

43. C# 11 generic math là gì?

Static interface (INumber, IAdditionOperators<T,T,T>...) cho phép generic over types có operator:

public static T Sum<T>(IEnumerable<T> nums) where T : INumber<T> =>
    nums.Aggregate(T.Zero, (a, b) => a + b);

44. out keyword trong C# generic interface — khác out parameter?

Khác hoàn toàn:

  • out T trong interface IEnumerable<out T>: variance annotation (covariant).
  • out T x trong method parameter: parameter modifier (must assign in method).

Cùng keyword, ngữ cảnh khác.

45. Erased generic gây "type leak" không?

Có thể. Ví dụ TS instanceof Array không phân biệt Array<string>Array<number>. → Cần custom guard hoặc schema validation runtime.

Tiếp theo: chủ đề cuối — Nuxt 4

© 2026 .NET Fresher Guide. All rights reserved.

Về Trang Web

Hướng dẫn toàn diện để chuẩn bị phỏng vấn vị trí .NET Fresher với nội dung từ lý thuyết đến thực hành.