CodeGym /Các khóa học /C# SELF /Làm việc với null: toán tử ??, ?., ?, !, default

Làm việc với null: toán tử ??, ?., ?, !, default

C# SELF
Mức độ , Bài học
Có sẵn

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 (??)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";
Kiểm tra null kiểu truyền thống

Toán tử ?? giúp bạn viết ngắn gọn hơn:

string userName = null;
string displayName = userName ?? "Khách";
Dùng ?? để đặt giá trị mặc định

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";
Chuỗi toán tử ??

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;
Kiểm tra null kiểu truyền thống trước khi truy cập property

Toán tử ?. giúp bạn viết đơn giản hơn:

User user = null;
string displayName = user?.Name;
Toán tử điều kiện null ?.

Nếu object usernull, 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];
Chuỗi ?. để truy cập an toàn property lồng nhau

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ử ?.?? phối hợp cực tốt:


string display = user?.Name ?? "Không rõ";
In ra an toàn với giá trị mặc định thay thế

Nếu user hoặc user.Namenull, 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
Dùng default để reset biến

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 ?, !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?
int?
Kiểu giá trị nullable Mọi nơi Có thể gán null
string?
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
default
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 ?, !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.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION