1. Toán tử kết hợp với null (??)
Kiến thức về nullable-type của bạn sẽ chưa trọn vẹn nếu không biết viết code ngắn gọn và an toàn. Trong C#, có hai toán tử cực kỳ hữu ích cho việc này: kết hợp với null (??) và toán tử điều kiện null (?.).
Toán tử ?? cho phép bạn đặt “giá trị mặc định” cho biến có thể là null.
Giả sử bạn có tên người dùng, có thể là null. Nếu nó thực sự là null, bạn muốn hiển thị "Khách". Ví dụ:
string userName = null;
string displayName = userName != null ? userName : "Khách";
Toán tử ?? giúp bạn viết ngắn gọn hơn:
string userName = null;
string displayName = userName ?? "Khách";
Cách hoạt động:
- Nếu biểu thức bên trái không phải null, nó sẽ được trả về.
- Nếu bên trái là null, sẽ lấy giá trị bên phải.
Thêm ví dụ:
int? age = null;
int displayAge = age ?? -1; // -1 — giá trị mặc định
Console.WriteLine(displayAge); // In ra -1
string input = null;
string name = input ?? "Khách";
Console.WriteLine($"Chào, {name}!"); // Chào, Khách!
Chuỗi toán tử
Có thể lồng ?? thành chuỗi:
string result = str1 ?? str2 ?? "Mặc định";
Nếu str1 không phải null, sẽ dùng nó. Nếu không — str2, nếu cả hai đều null — thì lấy chuỗi "Mặc định".
2. Toán tử điều kiện null (?.)
Một tình huống phổ biến khác — gọi method hoặc truy cập property của object, chỉ khi object đó không phải null. Ví dụ:
User user = null;
string displayName = user != null ? user.Name : null;
Toán tử ?. giúp bạn viết đơn giản hơn:
User user = null;
string displayName = user?.Name;
Nếu object user là null, biểu thức sẽ không gây lỗi mà chỉ trả về null.
Ví dụ:
User user = null;
// Không dùng ?. — sẽ lỗi
// Console.WriteLine(user.Name); // NullReferenceException
Console.WriteLine(user?.Name); // An toàn — in ra chuỗi rỗng hoặc không gì cả
Console.WriteLine(user?.GetProfileInfo()); // Tương tự
User[] users = null;
int? count = users?.Length; // null nếu users == null
Chuỗi toán tử
Có thể xây dựng cả "chuỗi":
string domain = company?.Director?.Email?.Split('@')?[1];
Nếu bất kỳ phần nào trong chuỗi là null, biểu thức sẽ trả về null chứ không ném exception.
Kết hợp với ??
Hai toán tử ?. và ?? phối hợp cực tốt:
string display = user?.Name ?? "Không rõ";
Nếu user hoặc user.Name là null, sẽ in ra "Không rõ".
3. ! là gì và dùng để làm gì
Toán tử bỏ qua cảnh báo về null
Trong các phiên bản C# hiện đại (khi bật NRT), compiler sẽ cảnh báo nếu bạn truy cập biến có thể là null. Nhưng đôi khi bạn chắc chắn mọi thứ đều ổn. Khi đó dùng toán tử bỏ qua !.
string? possibleNull = GetUserNameMaybeNull();
Console.WriteLine(possibleNull.Length); // Warning: có thể null
Console.WriteLine(possibleNull!.Length); // Compiler im lặng, nhưng nếu là null — sẽ ném exception
Lưu ý: ! không bảo vệ khỏi lỗi — nó chỉ nói với compiler "tin tôi đi". Nếu biến thực sự là null, sẽ bị NullReferenceException.
Khi nào không nên dùng
Đừng dùng ! bừa bãi. Code đẹp là hạn chế tối đa việc dùng nó. Tốt nhất là viết lại code để null không thể xảy ra hoặc được xử lý rõ ràng.
4. default — lấy giá trị "chuẩn" của kiểu dữ liệu
Đôi khi bạn chỉ muốn "reset" biến về trạng thái ban đầu, nhất là khi không muốn tự gán 0, false hoặc null.
Để làm vậy, có từ khóa default.
int a = default; // a == 0
bool flag = default; // flag == false
string s = default; // s == null
double? d = default; // d == null
Trong mini-app của bạn, ví dụ, có thể reset tên hoặc tuổi:
userName = default; // null
userAge = default; // null (nếu userAge là int?)
5. Khác biệt và lưu ý: ?, !, default
Ngay cả dev có kinh nghiệm đôi khi cũng bối rối khi thấy ?, ! và default cạnh nhau. Cùng phân biệt nhé.
? — bạn cho phép null
- Với kiểu giá trị: int? x — giờ x có thể là null.
- Với kiểu tham chiếu: string? s — chỉ rõ biến có thể là null (ở chế độ NRT).
! — bạn khẳng định sẽ không có null
- user!.Name — bạn cam kết với compiler rằng user chắc chắn không phải null.
- Chỉ hoạt động ở chế độ Nullable Reference Types.
default — bạn xin giá trị "mặc định"
- int x = default; — x sẽ là 0
- string s = default; — s sẽ là null
So sánh:
| Cú pháp | Ý nghĩa | Dùng ở đâu? | Liên quan gì đến null? |
|---|---|---|---|
|
Kiểu giá trị nullable | Mọi nơi | Có thể gán null |
|
Kiểu tham chiếu nullable (NRT) | Chế độ NRT | Có thể gán null |
|
Null-forgiving operator | Chế độ NRT | Bỏ qua cảnh báo |
|
Giá trị mặc định | Mọi nơi | Với kiểu tham chiếu — là null |
6. Lỗi thường gặp khi dùng ?, ! và default
Lỗi #1: nghĩ rằng ! "chữa lành" null.
Thực ra ! chỉ làm compiler không cảnh báo nữa. Nếu giá trị vẫn là null, chương trình sẽ crash với NullReferenceException.
Lỗi #2: quên kiểm tra .HasValue trước khi dùng .Value.
Đặc biệt với int?, bool? và các kiểu nullable khác. Không kiểm tra có thể bị InvalidOperationException.
Lỗi #3: dùng default ở nơi cần "ý nghĩa đặc biệt" của số 0.
Ví dụ, 0 hoặc false có thể là giá trị hợp lệ, không phải "trống". Điều này dễ gây lỗi logic.
Lỗi #4: không dùng ? cho kiểu tham chiếu ở chế độ NRT — hoặc lạm dụng nó.
Có người quên ?, compiler báo hàng loạt cảnh báo. Có người lại gắn ? mọi nơi, kể cả chỗ không thể null. Cả hai đều làm code khó đọc và kém an toàn.
GO TO FULL VERSION