Phân cấp lớp trong C#

Tính kế thừa (Inheritance) là một trong bốn trụ cột quan trọng của lập trình hướng đối tượng (OOP).

  • Tính đóng gói (Encapsulation).
  • Tính kế thừa (Inheritance).
  • Tính đa hình (Polymorphirsm).
  • Tính trừu tượng (Abstraction).

Nếu chưa hiểu rõ về lập trình hướng đối tượng thì bạn nên tham khảo bài viết dưới đây trước:

Lập trình hướng đối tượng (OOP) trong C# | Comdy
Lập trình hướng đối tượng (OOP) trong C# là gì? 5 khái niệm và 4 tính chất quan trọng của lập trình hướng đối tượng là gì?

Tính kế thừa là khả năng tạo một lớp mới dựa trên một lớp có sẵn. Lớp có sẵn là lớp cha, lớp mới là lớp con và lớp con thừa kế các thành phần được định nghĩa ở lớp cha.

Hãy xem ví dụ về hệ thống phân cấp lớp sau đây:

public class Small
{ 

}
public class Big: Small
{

}
public class Bigger : Big
{ 
    
}

Theo ví dụ trên, Small là lớp cơ sở cho lớp Big và lớp Big là lớp cơ sở cho lớp Bigger. Điểm cần nhớ ở đây là một lớp dẫn xuất sẽ luôn có một cái gì đó nhiều hơn một lớp cơ sở, vì vậy lớp cơ sở tương đối nhỏ hơn lớp dẫn xuất.

Bây giờ, hãy xem xét việc khởi tạo sau:

Khởi tạo class trong hệ thống phân cấp lớp trong C#

Như bạn có thể thấy ở trên, một lớp cơ sở có thể chứa một lớp dẫn xuất nhưng một lớp dẫn xuất không thể chứa một lớp cơ sở.

Nói cách khác, có thể tạo thể hiện của lớp con và gán cho một biến của lớp cha nhưng không thể tạo thể hiện của lớp cha và gán cho một biến của lớp con.

Bây giờ, chúng ta hãy tìm hiểu về hiệp phương sai và chống chỉ định trong C#.

Hiệp phương sai trong C#

Hiệp phương sai (Covariance) cho phép bạn truyền một kiểu dẫn xuất cho một phương thức yêu cầu một kiểu cơ sở.

Về cơ bản, lớp dẫn xuất là lớp cơ sở được bổ sung thêm các chức năng. Vì vậy, hiệp phương sai cho phép bạn sử dụng một lớp dẫn xuất để thay cho một lớp cơ sở.

Hiệp phương sai có thể được áp dụng trên delegate, generic, array, interface, v.v.

Small small1 = new Big();
Small small2 = new Bigger();
Big big = new Bigger();

object[] objs = new string[10];

Hiệp phương sai với delegate

Nếu bạn chưa đọc bài hướng dẫn về delegate thì có thể tham khảo tại đây trước khi tiếp tục nhé:

Delegate trong C# | Comdy
Delegate trong C# là gì? Delegate trong C# dùng để làm gì? Cách sử dụng Delegate trong C#.

Hiệp phương sai với delegate cho phép linh hoạt trong kiểu trả về của các phương thức delegate. Hãy xem ví dụ sau:

public delegate Small CovarDel(Big mc);

class Program
{
    static Big Method1(Big bg)
    {
        Console.WriteLine("Method1");
    
        return new Big();
    }
    
    static Small Method2(Big bg)
    {
        Console.WriteLine("Method2");
    
        return new Small();
    }
        
    static void Main(string[] args)
    {
        CovarDel del = Method1;

        Small sm1 = del(new Big());

        del = Method2;
        Small sm1 = del(new Big());
    }
}

Kết quả khi biên dịch và thực thi chương trình như sau:

Method1
Method2

Như bạn có thể thấy trong ví dụ trên, delegate mong đợi một kiểu trả về là Small (lớp cơ sở) nhưng chúng ta vẫn có thể gán Method1 trả về kiểu Big (lớp dẫn xuất) và Method2 có chữ ký giống như mong đợi của delegate.

Do đó, hiệp phương sai cho phép bạn gán một phương thức cho delegate có kiểu trả về ít dẫn xuất hơn.

Chống chỉ định trong C#

Chống chỉ định (Contravariance) được áp dụng cho các tham số. Chống chỉ định cho phép một phương thức với tham số của lớp cơ sở được gán cho một delegate yêu cầu ​​tham số của lớp dẫn xuất.

Tiếp tục với ví dụ trên, thêm phương thức Method3 có kiểu tham số khác với delegate như sau:

delegate Small CovarDel(Big mc);

class Program
{
    static Big Method1(Big bg)
    {
        Console.WriteLine("Method1");
        return new Big();
    }
    
    static Small Method2(Big bg)
    {
        Console.WriteLine("Method2");
        return new Small();
    }

    static Small Method3(Small sml)
    {
        Console.WriteLine("Method3");
        
        return new Small();
    }
    
    static void Main(string[] args)
    {
        CovarDel del = Method1;
        del += Method2;
        del += Method3;

        Small sm = del(new Big());
     }
}

Kết quả khi biên dịch và chạy chương trình:

Method1
Method2
Method3

Như bạn có thể thấy, Method3 có một tham số của lớp Small trong khi delegate yêu cầu một tham số của lớp Big. Tuy nhiên, bạn có thể sử dụng Method3 với delegate.

Bạn cũng có thể sử dụng hiệp phương sai và chống chỉ định trong cùng một phương thức như dưới đây.

delegate Small CovarDel(Big mc);

class Program
{
    static Big Method4(Small sml)
    {
        Console.WriteLine("Method4");
    
        return new Big();
    }

    static void Main(string[] args)
    {
        CovarDel del = Method4;
    
        Small sm = del(new Big());
    }
}

Kết quả khi biên dịch và chạy chương trình:

Method4

Có bạn nào bị nhức đầu, chóng mặt khi đọc tới đây không? Hãy để lại comment bên dưới cho mọi người biết nhé.

Lập Trình C#Lập Trình C# Cơ Bản
Bài Viết Liên Quan:
Tạo tập tin Zip với .NET 5
Trung Nguyen 11/11/2021
Tạo tập tin Zip với .NET 5

Trong bài viết này, chúng ta sẽ tìm hiểu lớp tiện ích ZipFile trong C#, cách nén tập tin và thư mục, cùng với giải nén tập tin zip.

Đọc và ghi file Excel trong C#
Trung Nguyen 29/10/2021
Đọc và ghi file Excel trong C#

Bài viết này sẽ giới thiệu cách đơn giản nhất mà tôi đã tìm thấy để đọc và ghi file Excel bằng C# sử dụng ExcelMapper.

Làm việc với PriorityQueue của .NET 6
Trung Nguyen 25/10/2021
Làm việc với PriorityQueue của .NET 6

Bài viết này sẽ giúp bạn tìm hiểu PriorityQueue của .NET 6 là gì, cách chúng ta thêm các phần tử và cách chúng ta có thể xếp hàng lại cho các phần tử.

Hướng dẫn nhanh và ví dụ về pattern matching trong C#
Trung Nguyen 23/10/2021
Hướng dẫn nhanh và ví dụ về pattern matching trong C#

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