Nhìn bề ngoài, int, struct, class chỉ khác nhau ở syntax. Nhưng phía dưới CLR (Common Language Runtime), Value Type và Reference Type được cấp phát, copy và lưu trữ theo hai cách hoàn toàn khác nhau.
Cú lừa của dấu "="
Có bao giờ nhìn hai đoạn code này và nghĩ chúng hoạt động giống nhau chưa?
int a = 10; int b = a; b = 20;
và:
User user1 = new User(); User user2 = user1; user2.Name = "Duy";
Nhìn qua đều là biến mới = biến cũ, nhưng kết quả runtime lại khác hoàn toàn.
Value Type - copy toàn bộ giá trị
Ví dụ:
int a = 10; int b = a; b = 20;
Kết quả:
a = 10 b = 20
Vì với Value Type, dấu "=" sẽ copy toàn bộ dữ liệu.
Nghĩa là:
a ↓ 10 b ↓ 10
Sau khi copy, a và b hoàn toàn độc lập nhau. Đây là cách hoạt động của: int, double, bool, char, struct
Reference Type - copy địa chỉ memory
Ví dụ:
User user1 = new User(); User user2 = user1;
Lúc này:
user1 ↓ Heap Memory user2 ↓ Heap Memory
Cả hai biến đang cùng trỏ tới một object trong memory.
Nghĩa là:
user2.Name = "Duy";
thì:
user1.Name
cũng đổi theo.
Đây là lý do rất nhiều bug “ủa sao object tự đổi?” xuất hiện.
Stack và Heap - hiểu lầm phổ biến nhất
Rất nhiều người học kiểu:
Value Type -> Stack
Reference Type -> Heap
Không hoàn toàn đúng.
Ví dụ:
class User
{
public int Age { get; set; }
}
Age vẫn là Value Type.
Hoặc:
struct Point
{
public int X;
}
Nếu struct nằm bên trong object khác thì nó cũng có thể nằm trên Heap.
Điều quan trọng nhất không phải nằm ở đâu, mà là nó được copy kiểu gì
Value Type → copy giá trị
Reference Type → copy reference
Đây mới là bản chất thật sự.
Vì sao struct thường nhanh hơn class?
Vì Value Type thường không cần allocate object riêng trên Heap, ít tạo áp lực cho Garbage Collector copy trực tiếp dữ liệu. Nhưng đây cũng là con dao hai lưỡi.
Ví dụ struct quá lớn:
50 fields 100 fields
Thì mỗi lần copy sẽ rất tốn cost. Đây là lý do Microsoft thường khuyên Struct nên nhỏ và immutable. Việc truyền parameter cũng bị ảnh hưởng
Ví dụ:
void Change(int number)
{
number = 100;
}
Gọi:
int x = 10; Change(x);
Kết quả:
x = 10
Vì Value Type bị copy khi truyền parameter. Nhưng với class:
void Change(User user)
{
user.Name = "Duy";
}
Thì object thật sự bị sửa. Đây là chỗ rất nhiều người mới học C# bị nhầm.
string là trường hợp khá đặc biệt
string là Reference Type.
Nhưng:
string a = "hello"; string b = a; b = "world";
Kết quả:
a = hello b = world
Nhìn giống Value Type.
Lý do là vì string immutable. Mỗi lần thay đổi string, CLR sẽ tạo object mới thay vì sửa object cũ. Đây là thứ rất nhiều người hiểu nhầm khi mới học C#.
Kết luận
Nhìn bề ngoài: int, struct, class chỉ khác nhau ở syntax. Nhưng phía dưới CLR:
- Value Type copy dữ liệu thật
- Reference Type copy địa chỉ memory
Và đây là lý do rất nhiều behavior trong C# hoạt động khác nhau:
- Assign object
- Truyền parameter
- Memory allocation
- Performance
- Garbage collection
Hiểu được chuyện này không giúp code CRUD nhanh hơn. Nó giúp biết chính xác:
- Vì sao object bị đổi theo
- Vì sao data không update
- Vì sao memory tăng
- Vì sao struct và class hoạt động khác nhau
Nó chỉ là CLR đang quản lý dữ liệu theo hai cơ chế hoàn toàn khác nhau phía dưới runtime.
No comments yet. Be the first to comment!