[DOTNETVN] Tìm hiểu về delegate trong C#

Trong bài viết này tôi sẽ giới thiệu sơ lượt về delegate, cách sử dụng delegate trong C#.

Nghe nhiều bạn dev mỗi lần nhắc tới delegate thì có phần mù mờ với khái niệm này, có bạn có thể nói được lý thuyết nhưng lại tỏ ra lúng túng khi thực hành, không biết áp dụng như thế nào.

Hy vọng qua bài viết này có thể giúp các bạn thêm phần nào hiểu rõ hơn về delegate cũng như biết cách sử dụng delegate như thể nào.

1. Delegate là gì ? khi nào nên dùng delegate ?

- Delegate là một kiểu dữ liệu tham chiếu (reference type) bắt đầu xuất hiện từ phiên bản C# 2.0. Thay vì tham chiếu đến một đối tượng nào đó như các kiểu reference type khác thì delegate tham chiếu đến hàm (phương thức) và nó được gọi là đóng gói hàm. Nó tương tự như khái niệm con trỏ hàm trong C++.

- Delegate thường được dùng để tạo các sự kiện (event là một ứng dụng phổ biến của delegate) và các hàm callback cho chương trình.

- Cú pháp tạo một deletagte: [modifier] delegate return-type Identifier ([formal-parameters])

modifier: phạm vi hoạt động (private, public, protected, internal).

return-type: kiểu trả về (void, int,...).

Indentifier: tên delegate.

formal-parameters: danh sách các tham số (có thể có hoặc không).

Ví dụ: public delegate void PrintHelloWorld(string message); delegate này đại diện cho các phương thức có 1 tham số đầu vào là kiểu string và kiểu dữ liệu trả về là void

- Khi nào nên dùng delegate:

Delegate được dùng để xác định kiểu của các phương thức dùng để quản lý các sự kiện hoặc để cài đặt các hàm callback trong ứng dụng. Chúng cũng được dùng để xác định các phương thức chưa biết trước vào lúc thiết kế (có nghĩa là chỉ biết vào lúc chạy).

2. Ví dụ

Xét bài toán sau, cho một đối tượng tên nhân viên. Xây dựng lớp mảng nhân viên với phương thức sắp xếp nhân viên tăng dần theo độ tuổi, vậy chúng ta sẽ ứng dụng delegate để giải bài này thế nào ?

1. Ở đây tôi sẽ tạo một lớp có tên là NhanVien

public class NhanVien
{
    public int Id { get; set; }
    
    public string Name { get; set; }
    
    public int Age { get; set; }

    public NhanVien()
    {
        Id = new Ramdom().Next(1,999);
        Name = string.Empty;
    }

    public NhanVien(string name, int age)
    {
        Id = new Ramdom().Next(1,999);
        Name = name;
        Age = age;
    }

    public NhanVien(NhanVien nv)
    {
        Id =new Ramdom().Next(1,999);
        Name = nv.Name;
        Age = nv.Age;
    }

    public void NhapNhanVien()
    {
        Console.WriteLine("nhap ten nhan vien");
        Name = Console.ReadLine();
        Console.WriteLine("nhap tuoi nhan vien");
        Age = Console.ReadLine();
    }
}

2. Tôi sẽ tạo tiếp một lớp có tên là MangNhanVien

public class MangNhanVien
{
        //khai báo 1 delegate có tên là so sánh với kiểu trả về là bool và 2 tham số đầu vào kiểu object
        public delegate bool SoSanhDelegate(object x, object y);
        
        NhanVien[] _array ;
        
        int _count;
        public int Count
        {
            get { return _count; }
            set { _count = value; }
        }

        public MangNhanVien()
        {
            _count = 0;
        }
        public MangNhanVien(int n)
        { 
            _array[0] = new NhanVien();
            for (int i = 1; i < n; i++)
                _array[i] = new NhanVien();
        }
        public void NhapMangNhanVien()
        {
            Console.WriteLine("nhap so luong nhan vien trong mang);
            _count = int.Parse(Console.ReadLine());
            _array = new NhanVien[_count];
            for (int i = 0; i < _count; i++)
            {
                Console.WriteLine("nhap nhan vien a[{0}]",i);
                _array[i] = new NhanVien();
                _array[i].NhapNhanVien();
            }
        }
        public void XuatMangNhanVien()
        {
            for (int i = 0; i < count; i++)
            {
                int id = array[i].Id;
                string name = array[i].Name;
                int age = array[i].Age;
                Console.WriteLine("array[{0}] = ({1} - {2} - {3})", i, id, name,age);
            }
        }
        
        public bool SoSanh(object x, object y)
        {
            NhanVien nvX = (NhanVien)x;
            NhanVien nvY = (NhanVien)y;
            return nvX.Age > nvY.Age;
        }
        
        public void SapXep(SoSanhDelegate delegateFunc)
        {
            for (int i = 0; i < _count-1; i++)
                for (int j = i+1; j<_count; j++)
            {
                if (delegateFunc(array[i], array[j]))
                {
                    NhanVien nvTemp = new NhanVien(array[i]);
                    array[i] = array[j];
                    array[j] = nvTemp;
                }
            }
        }
}

Ở đây các bạn chú ý cho tôi hàm sắp xếp và hàm so sánh, ở hàm sắp xếp tôi truyền vào 1 tham số là cái delegate được khai báo ở trên. Lúc này nhìn vào dòng if(delegateFunc(array[i], array[j])) các bạn sẽ thấy rằng rõ ràng ở đây trong lúc code (thiết kế) bạn hoàn toàn không biết chính xác phương thức này sẽ làm gì cho đến khi nó được thực thi, hàm so sánh tôi viết dùng cho trường hợp so sánh tuổi bạn hoàn toàn có thể tạo thêm nhiều hàm nữa để tạo thêm các điều kiện sắp xếp khác nhau cho mảng. Bên dưới là cách sử dụng

class Program
{
    static void Main(string[] args)
    {
        MangNhanVien array = new MangNhanVien();
        array.NhapMangNhanVien();
        array.XuatMangNhanVien();
        array.sapxep(array.SoSanh); // ở đây tham số sẽ là hàm so sánh trong lớp mảng nhân viên
        array.XuatMangNhanVien();
        Console.ReadLine();
    }
}

Hy vọng qua bài viết này các bạn sẽ nắm được cơ bản về cách sử dụng delegate. Nếu có thắc mắc hoặc đóng góp để cải thiện bài viết vui lòng comment bên dưới nhé wink

Thông tin bài viết