String.Format và string interpolation – C# best practices

0

Nhu cầu định dạng và sử dụng chuỗi ký tự phát sinh từ những bài học lập trình đầu tiên, dù học ngôn ngữ nào cũng vậy. C# hỗ trợ cách định dạng chuỗi với phương thức Format của lớp string. Từ C# 6.0 xuất hiện cách định dạng string interpolation.

Bài viết này sẽ giới thiệu một số kinh nghiệm sử dụng chuỗi ký tự trong lập trình C#.

Không nên sử dụng string.Format()

String.Format() là phương thức định dạng chuỗi xuất hiện từ phiên bản đầu tiên của C# và vẫn còn tiếp tục được sử dụng và giới thiệu trong các sách dạy lập trình C#.

Nhiều phương thức khác như Console.Write/WriteLine còn tích hợp luôn với Format. Hẳn bạn nào khi mới học C# cũng có khoảng thời gian chật vật để tìm cách in ra console chuỗi ký tự có định dạng và chứa giá trị biến:

var name = "Donald Trump";
var town = "Washington DC";
var age = 18;
var message = string.Format("My name is {0}. I'm from {1}. I'm {2} years old", name, town, age);
Console.WriteLine(message);

Trong chuỗi trên, {0}, {1}, {2} được gọi là các placeholder. Giá trị của các biến sẽ được thay thế vào đúng vị trí tương ứng với placeholder: name là biến đầu tiên => số 0 => giá trị của nó sẽ điền vào chỗ {0}. Tương tự với các biến còn lại.

Phương thức này có thể dẫn đến một số “lỗi” thường gặp khiến bạn phải thử nghiệm ít nhất vài lần trước khi đạt được kết quả mong muốn.

Các vị trí placeholder trong chuỗi ký tự nơi cần điền giá trị của biến đều được đánh số. Điều bực mình nhất là compiler không hề giúp bạn kiểm tra số thứ tự của placeholder với số lượng tham số cung cấp. Trong ví dụ trên, nếu bạn quên truyền biến age, compiler bỏ qua nhưng chương trình sẽ bị lỗi lúc chạy.

Vấn đề nằm ở chỗ, các biến truyền vào cho Format thực chất là một mảng object. Ngoại trừ tham số đầu tiên là một chuỗi, phần còn lại trong mô tả tham số của Format chính là params object[]. Nghĩa là Format có thể nhận không hạn chế các biến trong một mảng tham số đầu vào. Các placeholder trong chuỗi thực chất chính là index của phần tử tương ứng trong mảng tham số.

Nếu lượng tham số truyền vào khá lớn, khả năng cực cao là bạn sẽ mắc lỗi!

Việc đọc code với string.Format khá khó chịu và khó theo dõi. Để hình dung ra kết quả, bạn phải làm đúng công việc của compiler: tự mình “nhặt” biến và “đặt” vào vị trí phù hợp.

Do đó, nếu bạn dùng C# 6.0 trở lên, hãy quên đi string.Format() và chuyển sang sử dụng cách thức định dạng mới: string interpolation.

Sử dụng string interpolation thay cho Format để định dạng chuỗi

C# 6.0 đưa ra một cách thức định dạng chuỗi hoàn toàn mới: string interpolation. Chuỗi ký tự được định dạng theo phương pháp này được gọi là interpolated string. Cùng chuỗi ký tự như trên nhưng được định dạng theo kiểu string interpolation:

var message = $"My name is {name}. I'm from {town}. I'm {age} years old";

Rõ ràng cách viết này dễ đọc, dễ viết hơn trước rất nhiều. Chắc chắn sẽ không có tình trạng nhầm lẫn như Format. Sự khác biệt là ký tự $ ở đầu chuỗi báo hiệu nó là một interpolated string. Bên trong chuỗi, thay vì sử dụng placeholder bạn sẽ viết trực tiếp biểu thức cần thiết vào đó.

Sử dụng biểu thức trong interpolated string

Trong cặp dấu ngoặc {} bạn không những có thể viết tên biến/hằng mà còn có thể viết bất kỳ biểu thức nào (sinh ra kết quả).

Lưu ý khái niệm biểu thức (expression). Nó phải là tổ hợp các phép toán (operator) có thể sinh ra kết quả và gán được cho một biến. Nếu không, nó không được gọi là expression và không thể đặt trong string interpolation.

// hằng cũng là một biểu thức
Console.WriteLine($"The value of pi is {Math.PI}"); 
// sử dụng phép toán điều kiện
Console.WriteLine($"The value of pi is {(round ? Math.PI.ToString() : Math.PI.ToString("F2"))}");
// sử dụng phép toán null coalescing và the null propagation
Console.WriteLine($"The customer's name is {c?.Name ?? "Name is missing"}");

Lưu ý toàn bộ biểu thức điều kiện

round ? Math.PI.ToString() : Math.PI.ToString("F2")

phải được đặt trong cặp dấu ngoặc (). Nếu thiếu cặp (), đoạn code trên sẽ báo lỗi. Lý do là biểu thức này chứa dấu :, vốn được C# hiểu là ký tự phân tách giá trị và chuỗi định dạng.

Sử dụng ToString để tránh box/unbox giá trị của biểu thức

Bạn nên hiểu rằng, đứng sau string interpolation lại chính là Format mà bạn đang muốn chối bỏ. Điều này đồng nghĩa rằng, giá trị các biểu thức bạn đưa vào interpolated string sẽ được xử lý giống hệt như đối với Format.

Nghĩa là, giá trị của biểu thức thuộc loại valute type sẽ bị box/unbox và biến đổi về string trước khi thay thế vào chuỗi. Ví dụ, các giá trị thuộc các kiểu cơ sở (loại struct và enum) chắc chắn sẽ bị box và unbox khi truyền vào interpolated string, giống hệt như khi sử dụng Format.

Math.PI có giá trị thuộc kiểu double, là một value type, nó sẽ bị box/unbox khi xử lý trong interpolated string. Để tránh tình trạng này, bạn có thể trực tiếp chuyển đổi nó về chuỗi như sau:

Console.WriteLine($"The value of pi is {Math.PI.ToString()}");
Console.WriteLine($"The value of pi is {Math.PI.ToString("F2")}");

Định dạng dữ liệu

Bạn vẫn có thể tiếp tục sử dụng cấu trúc định dạng dữ liệu giống hệt như trong string.Format():

Console.WriteLine($"The value of pi is {Math.PI:F2}");

Lưu ý dấu : nằm giữa giá trị và chuỗi định dạng F2. C# nhìn dấu : và quyết định đây sẽ là ký tự phân tách giữa giá trị và chuỗi định dạng. Do vậy, các biểu thức có chứa dấu : (như biểu thức điều kiện như ở trên) phải được đặt trong cặp dấu () để C# không bị nhầm lẫn.

Sử dụng interpolated string bên trong một interpolated string

Bạn thậm chí có thể viết các biểu thức bên trong interplated string mà giá trị hoặc tham số của nó cũng là một interpated string:

string result = default(string);
Console.WriteLine($@"Record is {(records.TryGetValue(index, out result) ? result : $"No record found at index {index}")}");

Lưu ý, trong những tình huống tương tự bạn phải viết thêm ký tự @ sau $.

Tuyệt đối không sử dụng interpolated string để viết truy vấn SQL trong chương trình.

Kết luận

String interpolation là cách định dạng chuỗi cực mạnh của C# và bạn nên khai thác nó thay cho cách định dạng cũ sử dụng phương thức Format.

Bên trong interpolated string bạn có thể sử dụng bất kỳ biểu thức C# hợp lệ nào.

Ngoài ra có một số tình huống đặc biệt cần lưu ý mà bạn đã biết ở trên.

Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần Bình luận ở cuối trang. Nếu cần trao đổi riêng, hãy gửi email hoặc nhắn tin qua form liên hệ. Nếu bài viết hữu ích với bạn, hãy giúp chúng tôi chia sẻ tới mọi người. Cảm ơn bạn!

Bình luận

avatar
  Đăng ký theo dõi  
Thông báo về