
Mỗi lần review code cho team mới, chúng tôi lại gặp đúng một kiểu vấn đề. Đồng nghiệp vẫn ghép chuỗi bằng dấu cộng, dòng code dài cả chục ký tự và xen lẫn nhiều biến khác nhau. Muốn biết câu hoàn chỉnh sẽ in ra là gì, người đọc phải lần từng dấu +. Cách viết này vẫn chạy đúng, nhưng đọc rất mệt, và nhiều người vẫn giữ nó chỉ vì đã quen tay.
Cách nối chuỗi truyền thống trông rất quen thuộc. Ví dụ “Xin chào ” + ten + “, bạn có ” + soDon + ” đơn hàng”. Mỗi biến chèn vào lại kéo theo một cặp dấu ngoặc kép và một dấu cộng. Với ba bốn biến thì còn dễ theo dõi. Nhưng khi ghép bảy tám biến, kèm vài lần gọi ToString(), người đọc phải dừng lại vài giây mới hình dung được kết quả cuối cùng.
Cái giá thật sự không nằm ở tốc độ
Nhiều người nghĩ nối chuỗi chậm hơn, nhưng chi phí thực sự nằm ở chỗ khác. Với chuỗi ghép đơn giản, trình biên dịch tối ưu khá tốt. Phần tốn kém hơn là code khó đọc, dễ thiếu dấu cách và dễ quên chuyển kiểu dữ liệu. Có lần chúng tôi phải truy tìm một lỗi hiển thị sai đơn hàng, và nguyên nhân chỉ là thiếu một khoảng trắng giữa hai chuỗi nối. Loại lỗi này gần như không xảy ra khi dùng cú pháp nội suy.
Phần lớn lập trình viên C# đều biết string interpolation vì đã đọc qua tài liệu chính thức. Vấn đề nằm ở lúc gõ code thật: tay vẫn bấm dấu cộng theo thói quen. Thói quen đó học từ những dự án cũ hoặc từ đoạn code sao chép của người khác. Thói quen kỹ thuật khó bỏ hơn ta tưởng, kể cả khi cách mới rõ ràng tiện hơn.
Một lỗi có thật chỉ vì thiếu khoảng trắng
Có lần chúng tôi mất gần một buổi sáng để tìm nguyên nhân một API trả về sai định dạng ngày. Thủ phạm chỉ là một dòng nối chuỗi viết từ hai năm trước. Dòng đó ghép sai thứ tự ngày và tháng, giữa hai biến có tên gần giống nhau. Lịch sử git cho thấy không ai đụng vào dòng ấy kể từ khi được viết. Nếu ngay từ đầu dùng $”{ngay:dd/MM/yyyy}”, tên biến và định dạng nằm sát nhau, lỗi kiểu này khó có cơ hội xảy ra.
Cũng giống việc xử lý exception đúng cách thay vì bọc try-catch khắp nơi, thói quen nối chuỗi tồn tại chủ yếu vì chưa ai đủ kiên nhẫn sửa lại từng dòng cũ. Bạn có thể tham khảo thêm cách xử lý exception gọn gàng hơn trong C# để thấy cùng tinh thần này áp dụng ở nhiều chỗ khác.
String interpolation là gì trong C#

String interpolation là cách nhúng trực tiếp biến vào bên trong chuỗi ký tự. Bạn không cần tách chuỗi rồi nối lại bằng dấu cộng. Cú pháp bắt đầu bằng dấu $ đặt ngay trước dấu ngoặc kép, còn biến nằm trong cặp ngoặc nhọn { }. Đoạn ví dụ trên khi viết lại sẽ thành $”Xin chào {ten}, bạn có {soDon} đơn hàng”.
So sánh hai đoạn cạnh nhau là thấy khác biệt ngay. Bản dùng dấu cộng buộc mắt nhảy qua lại giữa chuỗi và biến. Bản dùng $”…” gần như đọc được như một câu tiếng Việt. Người mới chỉ cần nhìn một lần là đoán được kết quả, không cần chạy thử.
Định dạng ngay trong ngoặc nhọn
Bên trong ngoặc nhọn không chỉ có tên biến trơn. Bạn còn có thể đặt biểu thức, ví dụ {soDon > 0 ? “có hàng” : “trống”} hoặc {soDon * donGia}. Cú pháp cũng cho phép định dạng ngay tại chỗ bằng dấu hai chấm, chẳng hạn {tongTien:C} để hiển thị tiền tệ, hoặc {ngayTao:dd/MM/yyyy} để hiển thị ngày theo kiểu Việt Nam. Không cần gọi thêm ToString() rườm rà như trước.
Có một chi tiết kỹ thuật đáng nhớ mà nhiều người hay bỏ qua. Mặc định, chuỗi nội suy lấy theo văn hoá hiện tại của hệ thống, gọi là culture. Vì vậy số thập phân hay ngày tháng có thể hiển thị khác nhau giữa các máy. Nếu muốn kết quả luôn giống nhau bất kể server được đặt ở đâu, hãy dùng string.Create(CultureInfo.InvariantCulture, $”…”) hoặc FormattableString.Invariant(…). Bỏ qua điều này, báo cáo xuất ra có thể sai định dạng số mà không ai hiểu vì sao.
Vài điểm mở rộng từ C# 10 trở đi
Từ C# 10, interpolation được mở rộng thêm. Nếu mọi phần bên trong ngoặc nhọn đều là hằng, bạn có thể gán chuỗi nội suy cho một const string. Bạn cũng có thể kết hợp với chuỗi verbatim bằng $@”…” để viết đường dẫn file hay chuỗi nhiều dòng mà vẫn nhúng biến được. Sang C# 11, raw string literal mở đầu bằng ba dấu ngoặc kép. Kết hợp với dấu $, nó giúp viết JSON hay câu SQL mẫu ngay trong code mà không phải escape dấu ngoặc kép. Chi tiết này dễ bị bỏ lỡ, vì ít ai đọc hết ghi chú phát hành của từng phiên bản.
Bỏ thói quen nối chuỗi cũ để đồng đội đọc code nhanh hơn

Lợi ích rõ nhất là giảm lỗi cú pháp và lỗi logic. Với dấu cộng, chỉ cần thiếu một khoảng trắng, quên một dấu ngoặc hay đặt biến sai vị trí là chuỗi in ra sai. Trình biên dịch không báo lỗi, vì về mặt cú pháp mọi thứ vẫn hợp lệ, chỉ sai về ý nghĩa. Interpolation gần như loại bỏ nhóm lỗi này, vì biến nằm ngay trong ngoặc nhọn và dễ soát bằng mắt hơn nhiều.
Lợi ích thứ hai là tốc độ đọc hiểu khi review. Đoạn nối chuỗi rối mắt thường là nơi lỗi ẩn nấp lâu nhất, nên đây là chỗ đầu tiên cần soát. Đổi sang interpolation giúp buổi review ngắn đi đáng kể, không còn phải dừng lại giải mã từng đoạn ghép chuỗi. Khi kết hợp với các nguyên tắc tránh sai lầm thường gặp khi làm backend .NET, cả nhóm soát code nhanh và chắc hơn.
Nhanh hơn không có nghĩa là luôn đúng
Có một hiểu lầm cần làm rõ: nhiều người cho rằng interpolation luôn nhanh hơn nối chuỗi bằng dấu cộng. Điều đó không hẳn đúng. Với vài ba biến, trình biên dịch C# thường sinh mã khá giống nhau cho cả hai cách, nên hiệu năng chênh lệch không đáng kể. Khác biệt thật sự nằm ở khả năng đọc và bảo trì, không phải ở tốc độ chạy. Nếu đang ghép chuỗi trong vòng lặp hàng nghìn lần, hãy cân nhắc StringBuilder, vì mỗi lần ghép đều tạo một đối tượng chuỗi mới trong bộ nhớ, dù dùng + hay $”…”.
Một sai lầm khác là nhồi quá nhiều biểu thức phức tạp vào một chuỗi nội suy, đến mức dòng code dài hơn cả câu văn gốc. Khi biểu thức cần gọi hàm, so sánh điều kiện hay xử lý nhiều bước, nên tính trước ra một biến riêng rồi mới đưa vào chuỗi. Mục tiêu của interpolation là code dễ đọc, không phải nhét mọi logic vào một dòng cho ngắn.
Bắt đầu từ đoạn code đang sửa dở, đừng đợi refactor toàn bộ

Bạn không cần đổi hết dự án cũ trong một buổi chiều. Lần tới khi mở một file cũ để sửa bug, hãy để ý đoạn nối chuỗi bằng dấu cộng nằm trong hàm đang làm việc, rồi đổi luôn sang $”…”. Cách làm dần dần này ít rủi ro hơn nhiều so với tìm-thay-thế hàng loạt trên cả codebase. Mỗi lần đổi, bạn chỉ cần build và test lại đúng phần vừa chạm vào.
Với dự án mới, chúng tôi khuyên đưa quy tắc này vào coding convention ngay từ đầu: mọi chuỗi ghép từ hai biến trở lên dùng string interpolation, trừ khi đang xử lý hiệu năng trong vòng lặp lớn thì chuyển sang StringBuilder. Quy tắc ngắn như vậy dễ nhớ và dễ áp dụng khi review.
Nếu team dùng Visual Studio hoặc Rider, bạn có thể tận dụng gợi ý tự động. Cả hai IDE đều gạch mờ những đoạn nối chuỗi bằng dấu cộng và đề nghị chuyển sang interpolation chỉ với Alt+Enter. Bật thêm quy tắc IDE0057 trong file .editorconfig, cả nhóm sẽ được nhắc mỗi khi vô tình quay lại thói quen cũ.
Tham khảo thêm cho dev .NET
Nếu bạn muốn viết code .NET gọn và dễ bảo trì hơn, đừng dừng ở một mẹo. Hãy tiếp tục tìm hiểu các chủ đề liên quan như so sánh LINQ method syntax và query syntax để biết khi nào nên dùng cách nào, hoặc 7 kinh nghiệm thực tế về LINQ trong C# và .NET. Mỗi mẹo nhỏ như interpolation cộng lại sẽ giúp codebase của bạn sạch hơn đáng kể theo thời gian. Ngoài ra, bạn có thể đọc thêm tài liệu chính thức của Microsoft về chuỗi nội suy để nắm đầy đủ các tuỳ chọn định dạng.


