Hướng dẫn nhanh và ví dụ về pattern matching trong C#

Hướng dẫn nhanh và ví dụ về pattern matching trong C#

Với mỗi bản phát hành mới của C#, pattern matching (khớp mẫu) được cải tiến cho các nhà phát triển C#. Mặc dù các nhà phát triển ngày nay không sử dụng rộng rãi khớp mẫu, nhưng chúng ta có thể sẽ thấy việc áp dụng nó tăng lên khi nhiều nhóm và ứng dụng chuyển từ .NET Framework (.NET 4.8) sang các phiên bản mới hơn (.NET 5+)

Giống như hầu hết các tính năng độc đáo của ngôn ngữ, luôn có phản ứng đầu tiên là chấp nhận nó, sử dụng nó ở mọi nơi hoặc hoàn toàn ghét nó. Bất kể chúng ta thuộc loại nào, chúng ta cần hiểu một số trường hợp sử dụng hàng ngày trong trường hợp chúng ta muốn làm việc với khớp mẫu C#.

Bài viết này sẽ trình bày một số ví dụ về các kịch bản khớp mẫu mà tôi thấy hữu ích và bạn có thể muốn xem xét sử dụng trong các dự án hiện tại hoặc tương lai của bạn.

Các kiểu dữ liệu

Đối với hướng dẫn này, chúng ta sẽ sử dụng các kiểu record sau.

abstract record Food;
record Pizza(params string[] Toppings) : Food;
record Burger(int NumberOfPatties = 1, bool HasCheese = true): Food;
record Chicken(CookKind Kind = CookKind.Fried): Food;

enum CookKind
{
    Fried,
    Grilled,
    Baked
}

Kết hợp kiểm tra và khai báo kiểu

Một trong những cách sử dụng mới yêu thích của tôi cho khớp mẫu liên quan đến một từ khóa cũ là ifvà một từ khóa mới là is, được áp dụng theo một cách mới và thú vị. Chúng ta hãy xem một số ví dụ.

Food food = new Pizza("pepperoni");

// check and declare a variable of a specific type
if (food is Pizza pizza)
{
    Console.WriteLine($"this pizza has {string.Join(", ", pizza.Toppings)}");
}

Chúng ta có thể kiểm tra xem biến có đáp ứng điều kiện cho một kiểu hay không và khai báo một biến để chúng ta sử dụng trong phạm vi câu lệnh if. Nếu các nhà phát triển sử dụng bất kỳ khớp mẫu nào trong mã của họ, thì hãy để nó là mẫu này.

Kiểm tra rỗng

Nullability là một tính năng mới hơn của C#, hy vọng sẽ giúp giảm kiểm tra null trong toàn bộ codebase của chúng ta bằng cách cung cấp các đảm bảo an toàn với null.

Hầu hết các codebase vẫn chưa kích hoạt tính năng này, vì vậy nhiều người trong chúng ta vẫn phải dựa vào việc kiểm tra các giá trị null. Chúng ta sẽ sử dụng lại từ khóa is và xem cách chúng ta có thể kiểm tra xem biến là null hay không null.

// check the variable is null
if (food is null)
{
    Console.WriteLine("It's Null!");
}

// check that the variable is something
if (food is object)
{
    
}

// same as "is object"
// but uses the object pattern
if (food is { })
{
    Console.WriteLine("Not Null!");
}

Các nhà phát triển lần đầu tiên nhìn thấy điều này sẽ hỏi, tại sao điều này lại tốt hơn toán tử ==hay !=? Nó không tốt hơn; nó chỉ là một cách tiếp cận khác với hy vọng làm cho mã dễ đọc hơn. Định nghĩa của con người có thể đọc được phụ thuộc vào chủ quan.

Tối ưu xử lý ngoại lệ

Kinh nghiệm đầu tiên của tôi với khớp mẫu là sử dụng từ khóa when để xử lý ngoại lệ Exception. Các thư viện kế thừa nổi tiếng với việc đưa ra các ngoại lệ chung với nhiều thông tin chi tiết hơn được tìm thấy trong InnerExceptionhoặc trong thuộc tính Message.

// refined exception handling
try
{
    // super complex legacy library
    // that throws one type of exception
}
catch (Exception e) 
    when (e.Message.Contains("Ah!"))
{
    // handle that strange exception
}

Trong ví dụ này, chúng ta sẽ chỉ bắt được một Exception theo nội dung tin nhắn cụ thể. Mã sẽ ném các ngoại lệ khác, cho phép chúng ta xử lý chúng sau này trong codebase của chúng ta.

Câu lệnh switch

Câu lệnh switch nhận được giải thưởng được cải thiện nhiều nhất khi nói đến việc bổ sung khớp mẫu. Chúng ta không còn phải giải quyết các câu lệnh switch trên các kiểu nguyên thủy. Bây giờ chúng ta có thể sử dụng các đối tượng phức tạp với khả năng lồng nhiều câu lệnh switch hơn.

var healthy = food switch
{
    Pizza p => false,
    Burger b => false,
    // branching into a sub pattern matching
    Chicken c => c switch
    {
        { Kind: CookKind.Fried } => false,
        _ => true
    }, 
    _ => false
};

Đặc điểm cơ bản cần lưu ý trong đoạn mã này là .NET sẽ đánh giá từng phần trong câu lệnh switch của chúng ta theo thứ tự mà nó được xác định. Hãy tưởng tượng các câu lệnh switch này tương tự như chiếc xe bus sẽ dừng ở các điểm dừng trên tuyến, với biến loại bỏ _, là điểm dừng cuối cùng trên tuyến.

Chúng ta cũng có thể thấy ví dụ về khai báo kiểu cho Pizza, BurgerChicken. Trong câu lệnh switch ở Chicken, chúng ta sử dụng khớp mẫu đối tượng để xác định loại gà.

Khớp mẫu đối tượng

Với C# 9, các nhà phát triển đã nhận được mô hình kết hợp đối tượng và một số từ khóa mới như andornhư một phần của khớp mẫu. Giải cấu trúc, một tính năng mặc định của kiểu record, thêm một khớp mẫu khác, như chúng ta sẽ thấy trong ví dụ ở bên dưới.

food = new Burger(3, true);
// terse if statements
if (food is Burger {NumberOfPatties: > 2, HasCheese: true})
{
    Console.WriteLine("Yum!");
}

// use the deconstruct method of
// our Burger record type to make for a
// terser if statment
if (food is Burger(> 2, true))
{
    Console.WriteLine("Yum!");
}

// filter by type and declare a variable
Food lunch = new Chicken(CookKind.Grilled);
if (food is Burger { NumberOfPatties: > 0 and < 3 } burger)
{
    Console.WriteLine($"{burger.NumberOfPatties} Patties For Me!");
}

if (lunch is Chicken {Kind: CookKind.Baked or CookKind.Grilled} chicken)
{
    Console.WriteLine("Eating Healthy!");
}

Những ví dụ này cho thấy từ khóa thích andorcó thể giảm nhiễu các câu lệnh logic của chúng ta như thế nào. Chúng ta cũng thấy sự xuất hiện lại của khai báo biến bằng cách thêm tên biến vào cuối khớp mẫu đối tượng của chúng ta.

Phần kết luận

Khớp mẫu là một chủ đề gây tranh cãi trong cộng đồng .NET, một số cho rằng nó “không còn giống C# nữa”, một số cho rằng đó là các chức năng làm cho“ngôn ngữ C# tốt hơn”.

Bất kể ý kiến ​​như thế nào, các tính năng này đã có sẵn trong C# 9 và bạn nên tìm hiểu cách khớp mẫu mới này. Có kỹ thuật hoặc cách tiếp cận nào với khớp mẫu mà tôi đã bỏ qua không?

Như mọi khi, cảm ơn bạn vì đã dành thời gian đọc bài viết này.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *