Tóm tắt cốt lõi
| Đặc điểm | List<T> | IList<T> |
| Bản chất | Class (concrete implementation) | Interface (contract) |
| Khởi tạo | new List<T>() | Không thể new IList<T>() |
| Kế thừa | Implements: IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable | Kế thừa: ICollection<T>, IEnumerable<T> |
| Phương thức mở rộng | Có thêm: AddRange, RemoveAll, Find, Sort, Reverse, BinarySearch, ConvertAll, GetRange, AsReadOnly, Capacity, TrimExcess | Chỉ các method interface cơ bản |
| Performance | Truy cập index nhanh (O(1)), cache-friendly | Truy cập qua interface (virtual call, chậm hơn nhẹ) |
Code minh họa
using System;
using System.Collections.Generic;
class Demo
{
static void Main()
{
// ❌ SAI: Không thể khởi tạo interface
// IList list = new IList(); // Compile Error
// ✅ ĐÚNG: Khai báo interface, khởi tạo concrete class
IList ilist = new List();
ilist.Add("Mark");
ilist.Add("John");
// ✅ ĐÚNG: Dùng concrete class trực tiếp
List list = new List();
list.Add("Mark");
list.Add("John");
// List có method mở rộng mạnh hơn
list.AddRange(new[] { "Alice", "Bob" });
list.RemoveAll(s => s.StartsWith("M"));
list.Sort();
// IList chỉ có method cơ bản
// ilist.AddRange(...); // ❌ Không compile
// ilist.Sort(); // ❌ Không compile
// Ép kiểu nếu cần method List
if (ilist is List concreteList)
{
concreteList.Sort();
}
}
}
Khi nào dùng List vs IList?
Dùng List<T> khi:
- Implementation nội bộ (private field, local variable).
- Cần method đặc thù:
Sort, Find, BinarySearch, Capacity, TrimExcess.
- Performance critical (tránh virtual call overhead).
- Return type của private/internal method.
Dùng IList<T> khi:
- Public API (return type, parameter type) - Program to interface.
- Cho phép thay đổi implementation sau này (List → Array, ImmutableList, CustomList).
- Dependency Injection, Repository pattern.
- Chỉ cần các operation cơ bản: Add, Remove, Indexer, Count, Contains.
Best Practice: API Design
// ❌ Trả về concrete type - tight coupling
public List GetUsers() { ... }
// ✅ Trả về interface - loose coupling
public IList GetUsers() { ... }
public IReadOnlyList GetUsers() { ... } // Tốt hơn: immutable intent
// Parameter: nhận interface rộng nhất có thể
public void ProcessItems(IEnumerable- items) { ... } // Chỉ đọc
public void ProcessItems(ICollection
- items) { ... } // Cần Count, Add/Remove
public void ProcessItems(IList
- items) { ... } // Cần indexer, Insert
IReadOnlyList<T> - Lựa chọn tốt hơn cho Read-only
// .NET 4.5+ - Chỉ đọc, không Add/Remove
public IReadOnlyList GetUsers()
{
return _users.ToList(); // hoặc _users.AsReadOnly()
}
// List implement IReadOnlyList
List list = new() { "a", "b" };
IReadOnlyList ro = list; // Implicit conversion
// ro.Add("c"); // ❌ Compile error
Array vs List vs IList
T[] implement IList<T> (nhưng Add/Remove throw NotSupportedException - fixed size).
List<T> implement IList<T> (dynamic size).
IList<T> là abstraction chung cho cả hai.
Performance Tip
// Tránh boxing/unboxing với value types
List list = new List(); // Good: int lưu trực tiếp
IList ilist = new List(); // OK: nhưng gọi qua interface virtual
IEnumerable enum = list; // OK: nhưng iterator pattern
// Benchmark: List nhanh hơn IList ~5-10% do devirtualization