Hiện tại, Microsoft đã triển khai Visual Studio 2019 sử dụng C# 8.0 với nhiều đặc trưng thú vị và hỗ trợ các nhà phát triển C# lập trình hiệu quả hơn. Tuy nhiên , trước khi khám phá các đặc trưng C# 8.0, chúng ta sẽ bắt đầu khám phá những đặc trưng hữu ích kể từ C# 6.0 (Visual Studio 2015) đến các phiên bản khác nhau của C# trong Visual Studio 2017 như C# 7.0, C# 7.1, C#7.2, C# 7.3.
Các thuộc tính chỉ đọc (Read-only auto-properties)
Một trong những thành phần quan trọng của một lớp là các thuộc tính (propeties) cho phép đọc và ghi thành phần dữ liệu (fields) của lớp một cách an toàn. Kể từ C# 6.0, chúng ta được phép định nghĩa các thuộc tính chỉ đọc như sau:
class Student { public string FirstName { get; } public string LastName { get; } }
Các thuộc tính chỉ đọc chỉ được phép khởi tạo giá trị trong phương thức khởi tạo của lớp, nếu khởi tạo giá trị trong phương thức khác của lớp thì sẽ phát sinh lỗi. Xét đoạn mã lớp Student:
class Student { public string FirstName { get; } public string LastName { get; } public Student(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public void ChangeName(string newLastName) { // Phát sinh lỗi CS0200 LastName = newLastName; } }
Khi thực thi sẽ phát sinh lỗi CS0200 như sau:
Các thuộc tính chỉ đọc cung cấp chúng ta cách một cú pháp cô đọng hơn để tạo các kiểu không đổi (immutable types).
C# 6.0 cũng cho phép chúng ta định nghĩa và khởi tạo các thuộc tính trong cùng một lệnh như sau:
public ICollection<double> Grades { get; } = new List<double>();
using static
using static cho phép chúng ta sử dụng các phương thức tĩnh (static methods) của một lớp nào đó một cách hiệu quả. Xem xét đoạn mã sau:
namespace HelloWord { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Console.ReadKey(); } } }
Hai đoạn mã trên chúng ta dùng các phương thức tĩnh WriteLine và ReadKey của lớp Console. Trong C# 6.0 chúng ta có thể khai báo lớp Console để dùng các phương thức tĩnh như sau:
using static System.Console; namespace HelloWord { class Program { static void Main(string[] args) { WriteLine("Hello World!"); ReadKey(); } } }
Toán tử điều kiện null
Cân nhắc đoạn mã sau đây:
Student st = new Student("Ngoc","Minh"); string first = st.FirstName; st = null; string firstNull = st.FirstName; WriteLine(first + " " + firstNull); ReadKey();
Khi thực thi đoạn mã trên sẽ phát sinh ngoại lệ:
Ngoại lệ phát sinh do khi gán giá trị của thuộc tính FistName đến biến firstNull, thể hiện st đã được gán đến giá trị null. C# 6.0 cung cấp toán tử ?. để xử lý vấn đề này:
string firstNull = st?.FirstName;
Nếu st khác null thì giá trị của FirstName sẽ được gán đến biến firstNull, ngược lại giá trị null sẽ được gán đến firstNull.
Nếu chúng ta muốn biến firstNull luôn luôn được nhận được một chuỗi bất kể st có là null hay không, chúng ta dùng kết hợp các toán tử ?. và ?? như sau:
string firstNull = st?.FirstName??"UnKnown";
Nếu st là null thì giá trị của firstNull sẽ là UnKnown, ngược lại sẽ là giá trị của thuộc tính FirstName.
Các toán tử điều kiện null cũng hữu dụng khi sử dụng các delegate và chúng ta sẽ bàn lại vấn đề này trong một bài viết khác của loạt bài viết về C#.
String interpolation
C# cho phép chúng ta kết hợp các biểu thức và chuỗi theo nhiều cách khác nhau như dùng toán tử + hay dùng mặt nạ định dạng:
Student st = new Student("Ngoc","Minh"); string first = st.FirstName; string last = st.LastName; // dùng toán tử + WriteLine("My firstname is " + first + " and my lastname is " + last); // dùng mặt nạ WriteLine("My firstname is {0} and my lastname is {1}",first, last);
C# 6.0 cung cấp một đặc trưng mới gọi là string interpolation cho phép chúng ta kết hợp chuỗi và biểu thức theo cách thức dễ đọc và tiện lợi như ví dụ sau:
// dùng string interpolation WriteLine($"My firstname is {first} and my lastname is {last}");
Để ý rằng, chuỗi của chúng ta bắt đầu bằng ký hiệu $ và liền ngày sau đó là dấu nháy kép để bắt đầu một chuỗi. Các biểu thức như first hay last được đặt trong cặp ngoặc{} và cú pháp đầy đủ của nội dung trong mỗi cặp ngoặc như sau:
{<Biểu_thức>[,<Số_kí_tự>][:<Định_dạng>]}
- Biểu_thức: Là biểu thức cần kết hợp với chuỗi.
- Số_kí_tự: Là giá trị quy định số ký tự sẽ được hiển thị từ Biểu_thức. Nếu Số_kí_tự là dương thì bắt đầu đếm Số_kí_tự từ bên phải, ngược lại, bắt đầu đếm từ bên trái.
- Định_dạng: Quy định hình thức hiển thị cho chuỗi Biểu_thức
Ví dụ:
const double Pi = 3.14; Console.WriteLine($"|{Pi,-7:f1}|{Pi,7}|");//Kết quả:|3,1 | 3,14|
Chi tiết hơn về string interpolation tham khảo tại https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
String Interpolation có thể được vận dụng trong việc viết các phương thức hay các thuộc tính chỉ đọc của lớp một cách nhanh chóng. Ví dụ chúng ta định nghĩa lại phương thức ToString() trong lớp Student như sau:
class Student { public string FirstName { get; } public string LastName { get; } public override string ToString() => $"{LastName}, {FirstName}"; public Student(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } }
Trong phương thức Main chúng ta có thể sử dụng phương thức ToString như sau:
Student st = new Student("Ngoc","Minh"); WriteLine(st.ToString());// Kết quả: Minh, Ngoc
Chúng ta cũng có thể áp dụng để định nghĩa thuộc tính FullName như sau
public string FullName => $"{FirstName} {LastName}";
1 Pingback