Menu

if else trong C#: chuỗi else if, điều kiện và lỗi thường gặp

Cách if, else if và else hoạt động trong C#: vì sao điều kiện phải là bool, kết hợp điều kiện bằng &&, || và !, khi nào cặp ngoặc nhọn quan trọng, guard clause thay cho lồng nhau sâu, và các lỗi nhầm = với == hay dấu chấm phẩy thừa.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Câu lệnh if chỉ chạy một khối code khi điều kiện đúng. else if thêm các phép kiểm tra khác, còn else bắt mọi trường hợp mà các phép kiểm tra trước đó bỏ qua.

Đầu ra:

Order 120: shipping 0
Order 75.50: shipping 4.99
Order 20: shipping 9.99

Các điều kiện được kiểm tra từ trên xuống và điều kiện đúng đầu tiên sẽ thắng. Một đơn hàng 120 khớp với >= 100 và không bao giờ tới phép kiểm tra >= 50, vì vậy điều kiện cụ thể nhất phải đặt trước. else if không phải là một từ khóa riêng: đó là một else mà phần thân là một if khác, nên C# không có elseif hay elif.

Điều kiện phải là bool

C# không bao giờ coi một số, một chuỗi hay một đối tượng là true hay false. Biểu thức trong ngoặc tròn phải có kiểu bool:

int count = 3;
if (count)          // error CS0029: Cannot implicitly convert type 'int' to 'bool'
if (count > 0)      // correct
if (name)           // error: a string is not a bool either
if (name != null)   // correct

Quy tắc này loại bỏ cả một nhóm bug thường gặp trong C và JavaScript, nơi 0, "" và null âm thầm được tính là false. Cái giá phải trả là bạn phải viết rõ phép so sánh mỗi lần, điều này cũng giúp người đọc tiếp theo thấy rõ ý định.

Kết hợp điều kiện với &&, || và !

&& (và), || (hoặc) và ! (phủ định) kết hợp các phép kiểm tra boolean. && và || đánh giá ngắn mạch: vế phải chỉ chạy nếu vế trái chưa quyết định được kết quả.

Đầu ra:

maya: welcome
invalid or banned account
invalid or banned account
omar: age 9 rejected
invalid or banned account

Lời gọi với null an toàn nhờ đánh giá ngắn mạch: khi username != null là false, username.Length không bao giờ được đánh giá, nên không có NullReferenceException. Đổi thứ tự thành username.Length >= 3 && username != null thì cùng lời gọi đó sẽ bị lỗi.

&& có độ ưu tiên cao hơn ||, nên a || b && c nghĩa là a || (b && c). Hãy thêm ngoặc tròn mỗi khi bạn trộn hai toán tử này; trình biên dịch không cần, nhưng người đọc thì cần. Các toán tử một ký tự & và | cũng dùng được với bool, nhưng chúng luôn đánh giá cả hai vế. Chỉ dùng chúng khi vế phải có tác dụng phụ bắt buộc phải xảy ra.

Ngoặc nhọn và quy tắc một câu lệnh

Ngoặc nhọn là tùy chọn khi một nhánh chỉ có một câu lệnh. Khi không có ngoặc nhọn, chỉ câu lệnh kế tiếp thuộc về if, bất kể thụt lề trông thế nào:

Đầu ra:

Reorder email sent
Stock: 12

"Reorder email sent" vẫn được in ra dù hàng tồn kho vẫn ổn: lệnh WriteLine thứ hai nằm ngoài if, dù thụt lề trông như ở trong. Một guard một dòng như if (x == null) return; không cần ngoặc nhọn cũng được; còn bất cứ nhánh nào có thể mọc thêm dòng thứ hai thì nên có.

Một bug liên quan là dấu chấm phẩy ngay sau điều kiện. if (stock < 5); kết thúc if bằng một câu lệnh rỗng, và khối phía sau luôn chạy bất kể điều kiện. Trình biên dịch báo cảnh báo CS0642, Possible mistaken empty statement, và bạn nên coi cảnh báo này như một lỗi.

= và == trong điều kiện

= dùng để gán, == dùng để so sánh. Với hầu hết các kiểu, lỡ viết = sẽ không biên dịch được, vì kết quả của phép gán là giá trị được gán và một int không phải là bool:

int score = 10;
if (score = 100) { }   // error CS0029: Cannot implicitly convert type 'int' to 'bool'

Với biến bool, bản thân phép gán cũng là một bool, nên lỗi gõ nhầm này vẫn biên dịch được:

Đầu ra:

Access granted
isAdmin is now True

Điều kiện đã ghi đè isAdmin rồi kiểm tra giá trị mới. Trình biên dịch có cảnh báo (CS0665, phép gán trong biểu thức điều kiện luôn là hằng số), nhưng việc build vẫn thành công. Với bool, hãy bỏ hẳn phép so sánh: if (isAdmin) và if (!isAdmin) dễ đọc hơn và không thể gõ nhầm kiểu này.

if lồng nhau và guard clause

Mỗi tầng lồng nhau là thêm một điều kiện người đọc phải ghi nhớ. Khi mỗi bước kiểm tra để loại đầu vào sai, hãy return sớm thay vì lồng luồng xử lý chính vào bên trong tất cả các bước đó:

Đầu ra:

ordered 2 x keyboard
error: no product
error: quantity must be positive
error: insufficient balance

Phiên bản lồng nhau của cùng phương thức này sẽ có ba tầng if, phần việc thật nằm ở khối trong cùng và ba nhánh else gỡ dần ở phía dưới. Với guard clause, mỗi quy tắc nằm cạnh thông báo lỗi của nó và dòng cuối cùng là trường hợp bình thường. Ý tưởng tương tự cũng áp dụng bên trong vòng lặp với continue.

Khai báo biến trong điều kiện

Một điều kiện có thể khai báo một biến có phạm vi bên trong if. Hai dạng phổ biến là out var từ một phương thức TryParse và mẫu kiểu với is:

Đầu ra:

42: positive number 42
abc: not a number
-7: number -7, not positive
string of length 5

TryParse trả về false thay vì ném ngoại lệ khi đầu vào sai, nên nó rất hợp để dùng với if. Trang chuyển đổi kiểu trình bày chi tiết các phương thức phân tích chuỗi.

Khi nào nên dùng cách khác

  • Chọn một trong hai giá trị: toán tử điều kiện condition ? a : b ngắn gọn hơn một câu if gán giá trị ở cả hai nhánh.
  • Nhiều nhánh theo một giá trị: câu lệnh switch so sánh một giá trị với các trường hợp hằng và dễ đọc lướt hơn mười dòng else if.
  • Ánh xạ một giá trị sang một kết quả: tra cứu bằng Dictionary thay thế được một chuỗi dài khi các nhánh chỉ khác nhau về dữ liệu.

Câu hỏi thường gặp

Viết else if trong C# như thế nào?

Viết else if thành hai từ: if (a) { ... } else if (b) { ... } else { ... }. Các điều kiện được kiểm tra từ trên xuống và chỉ nhánh đúng đầu tiên được chạy, nên hãy đặt điều kiện cụ thể nhất lên trước. C# không có từ khóa elif hay elseif.

Tại sao không viết được if (count) trong C#?

Điều kiện trong C# phải có kiểu bool. Khác với C và JavaScript, một int, một chuỗi hay một đối tượng không bao giờ được chuyển thành true hay false, nên if (count) báo lỗi CS0029, Cannot implicitly convert type 'int' to 'bool'. Hãy viết đúng phép kiểm tra bạn muốn: if (count > 0) hoặc if (name != null).

&& và & trong điều kiện if khác nhau thế nào?

&& đánh giá ngắn mạch (short-circuit): nếu vế trái là false thì vế phải không bao giờ được đánh giá, đó là lý do s != null && s.Length > 0 an toàn. & trên hai giá trị bool luôn đánh giá cả hai vế. Điều tương tự áp dụng cho || và |. Hãy dùng && và || trong điều kiện, trừ khi bạn cần tác dụng phụ của vế phải.

Câu lệnh if trong C# có bắt buộc dùng ngoặc nhọn không?

Không. Khi không có ngoặc nhọn, if chỉ điều khiển đúng một câu lệnh. Thụt lề dòng thứ hai không đưa nó vào nhánh đó, đây là nguồn bug kinh điển, nên phần lớn hướng dẫn phong cách code khuyên dùng ngoặc nhọn cho mọi nhánh.

Có thể viết if else trên một dòng trong C# không?

Để chọn một giá trị, hãy dùng toán tử điều kiện: string label = score >= 50 ? "pass" : "fail";. Để chạy câu lệnh, if (x) DoA(); else DoB(); viết trên một dòng là hợp lệ, nhưng khó đọc và khó mở rộng hơn một khối có ngoặc nhọn.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu