Pattern matching trong C# (phần 1)

Trước hết tại sao mình lại để nguyên cụm từ “pattern matching” mà không dịch ra tiếng việt? Thứ nhất dịch ra nó hơi sượng sượng, thứ hai theo mình thấy đây là thuật ngữ lập trình, chúng ta nên tập làm quen với cách gọi như vầy thay vì thứ gì cũng phải dịch 1-1.

Pattern matching là gì?

Tuy nói vậy nhưng mình vẫn thử dịch xem sượng sượng như nào nhé.
“Pattern matching” có thể dịch thành “Đối sánh theo mẫu”, hoặc “Khớp mẫu”.

Về cơ bản “Pattern matching” là quá trình lấy một biểu thức và kiểm tra xem nó có khớp với các tiêu chí nhất định, chẳng hạn như ‘là một kiểu được chỉ định’ hoặc ‘khớp với một giá trị hằng số được chỉ định’ hay không. Và đặc điểm của chúng là trả về kiểu boolean (vì khi so sánh khớp, chỉ có 2 kết quả - khớp hoặc không khớp).

Lịch sử của nó (bạn không cần đọc nó đâu)

Pattern matching là một tính năng tương đối mới trong C#. Nó được giới thiệu lần đầu ở phiên bản C# 7.0 và kể từ đó đã có những cải tiến bổ sung trong mỗi phiên bản kế tiếp của C#. Khi nói về pattern matching, C# có vô vàn pattern. Đó là lý do mình tính chia bài viết thành nhiều phần là vậy.

Dùng hay không dùng có ích lợi gì không?

Mình nói thẳng thế này, dùng - nếu bạn muốn code của bạn trông chuyên nghiệp hơn so với đồng nghiệp khác :v, hoặc bạn muốn giúp code bạn trở nên cô đọng và dễ đọc hơn so với việc sử dụng các câu lệnh if/else, switch truyền thống!

Ví dụ

Người bình thường viết như thế này

1
2
3
4
5
6
7
8
9
if (obj is Circle) {
Circle c = (Circle)obj;
Console.WriteLine($"Circle with radius {c.Radius}");
} else if (obj is Rectangle) {
Rectangle r = (Rectangle)obj;
Console.WriteLine($"Rectangle with width {r.Width} and height {r.Height}");
} else {
Console.WriteLine("Unknown shape");
}

Có chút tiến bộ, dùng câu lệnh switch viết như này :v

1
2
3
4
5
6
7
8
9
10
11
switch (shape) {
case Circle c:
Console.WriteLine($"Circle with radius {c.Radius}");
break;
case Rectangle r:
Console.WriteLine($"Rectangle with width {r.Width} and height {r.Height}");
break;
default:
Console.WriteLine("Unknown shape");
break;
}

Còn bạn sẽ viết như thế này (biểu thức switch, C# 8.0 trở lên hỗ trợ)

1
2
3
4
5
6
string shapeDescription = shape switch {
Circle c => $"Circle with radius {c.Radius}",
Rectangle r => $"Rectangle with width {r.Width} and height {r.Height}",
_ => "Unknown shape"
};

Mình thấy ngầu đét :)))

Lưu ý, việc dùng toán tử is phía trên, thật ra bạn cũng đang bước 1 bước vào pattern matching rồi đấy, nó là một toán tử dùng để kiểm tra xem một đối tượng có thuộc kiểu cụ thể hoặc bằng giá trị cụ thể hay không.

Bắt đầu xài nó nào - Constant pattern

Ở cấp độ đầu tiên, cũng là cái mình muốn giới thiệu bạn đầu tiên luôn nhá. À trong bài viết này, mình mặc định các bạn đã nắm về một số toán tử cơ bản của C# nhá, ví dụ toán tử is, ??, =>, …

Ở phần đầu tiên sẽ bắt đầu với “Constant pattern”. Hmmm, đừng bắt mình dịch, đại khái, đây là pattern so sánh với các giá trị không đổi, ví dụ null, số cho sẵn, … Xem ví dụ bạn sẽ hiểu hơn.

1
2
3
4
5
6
7
8
9
10
11
12
13
int number = 5;

// số 5 (biến number) chính là hằng số, nó không đổi
// khi dùng is để kiểm tra điều kiện khớp vs số 5 hay không
// thì người ta gọi đó là constant pattern
if (number is 5) {
Console.WriteLine("The number is five.");
}

if (number is not null)
{
Console.WriteLine("The number is not null.");
}

Hằng số ở đây không nhất thiết là giá trị, mà có thể là kiểu, toán tử is thường dùng để kiểm tra như vầy hơn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int? xNullable = 7;
int y = 23;
object yBoxed = y;

// nó còn hoặc động với boxing luôn nhá
if (xNullable is int && yBoxed is int)
{
Console.WriteLine("x is int");
}

// dùng với toán tử not
if (xNullable is not null)
{
Console.WriteLine("x is not null");
}

Còn đối với điều kiện mà nhiều giá trị cần kiểm tra mang tính chất là hằng số, nếu dùng câu lệnh switch sẽ dài dòng, chúng ta sẽ áp dụng constant pattern xài biểu thức switch để giúp code ngắn gọn hơn.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int dayOfWeek = 3;
string dayName = dayOfWeek switch
{
1 => "Monday",
2 => "Tuesday",
3 => "Wednesday",
4 => "Thursday",
5 => "Friday",
6 => "Saturday",
7 => "Sunday",
_ => "Invalid day"
};

Console.WriteLine(dayName);

Chốt lại với pattern này, thường thì mình thấy người ta hay xài để check null, kiểm tra có phải bằng null hay khác null không á. Bên cạnh đó còn kiểm tra xem nó có phải là đối tượng nào đó hay không.

Phần 1 kết thúc tại đây, mình sẽ ra bài tiếp nối hứa hẹn hấp dẫn hơn :v

 Comments
Comment plugin failed to load
Loading comment plugin