Archive

Posts Tagged ‘Delegate’

Delegates

Delegate tương tự như con trỏ hàm trong ngôn ngữ C và C++. Nhưng delegate thì hướng đối tượng và là một kiểu an toàn.
Một delagate được khai báo như sau:

 delegate result-type identifier ([parameters]);

result-type: Kiểu dữ trả về, kiểu này phải phù hợp với kiểu trả về của hàm được gọi.
identifier: tên của delegate.
parameters: các đối số truyền vào.
ví dụ: ta khai báo một delegate như sau:

 public delegate int add(int a, int b);

Ta khai báo một delegate add có kiểu trả về là kiểu int, với hai đối số kiểu int. Khi đó delegate này sẽ encapsulate những hàm mà có kiểu trả về là int và có hai đối số như trên.
Bạn theo dõi đoạn chương trình sau để hiểu rõ hơn:

 class Program
{
    public delegate int FuncAdd(int a, int b); //Khai báo delegate FuncAdd có kiểu trả về int và 2 đối số
    public static int Add(int a, int b)
    {
     return a + b;
    }
    public static void Solution()
    {
            FuncAdd funcAdd;
            funcAdd=Add;
            int result = funcAdd(3, 4);
            Console.WriteLine("{0}",result);
      }
    static void Main(string[] args)
    {
       Solution();
    }
}

Ở đây sau khi bạn gán funcAdd =Add thì lúc này funcAdd có tính chất tương tự như là của hàm Add.
Một điều đáng chú ý nữa là delegate cho phép bạn truyền đối số là một methods.
Lấy lại ví dụ trên ta có thể truyền cho funcAdd đối số là hàm Add(), và bạn có thể sữa lại hàm Solution vài chi tiết:

 public static void Solution()
{
    FuncAdd funcAdd = new FuncAdd(Add);
    int result = funcAdd(3, 4);
    Console.WriteLine("{0}",result);
}

Và bạn cũng có thể dùng delegate để làm một đối số của hàm. Ở đây chúng ta sẽ truyền đối số cho hàm Solution kiều delegate FuncAdd, và hàm Solution() có chỉnh sửa như sau:

 public static void Solution(FuncAdd funcAdd)
{
   int result = funcAdd(3, 4);
   Console.WriteLine("{0}",result);
}

Khi đó trong hàm main() chúng ta gọi hàm Solution() như sau:

   Solution(new FuncAdd(Add));

Không những vậy, bạn có thể sử dụng delegate để gọi đến nhiều methods khác nhau. Trong C#, delegate thì multicast, nghĩa là nó có thể trỏ đến hơn một phương thức trong một thời điểm (dựa trên kiểu System.MulticastDelegate). Một multicast delegate sẽ duy trì một danh sách các hàm và các hàm này sẽ được gọi khi delegate được gọi.

 class Program
    {
        public delegate int FuncAdd(int a, int b);

        public static int Add(int a, int b)
        {
            Console.WriteLine("Delegate called Add Function!");
            return a + b;
        }

        public static int Subtract(int a, int b)
        {
            Console.WriteLine("Delegate called Subtract Function!");
            return a - b;
        }
        public static void Solution(FuncAdd funcAdd)
        {
            int result = funcAdd(3, 4);
            Console.WriteLine("{0}",result);
        }

        static void Main(string[] args)
        {
            FuncAdd funcAdd = null;
            funcAdd +=new FuncAdd(Add);
            funcAdd += new FuncAdd(Subtract);
            Solution(funcAdd);
        }
    }

Trong ví dụ trên chúng ta dùng delegate để gọi tới hàm Add() và hàm Subtract(). Lưu ý, khi bạn dùng toán tử “+=” thì bạn cần khởi tạo giá trị ban đầu cho delegate là null, nếu không chương trình sẽ không cho phép bạn thực hiện. Và kết quả sau khi chạy chương trình bạn sẽ nhận hai dòng:
Delegate called Add Function!
Delegate called Subtract Function!

Ngoài ra, ai đã từng lập trình với Windows Form thì sẽ rất quen thuộc với câu lệnh:

btn.Click += new EventHandler(btn_Click);

Đây cũng là một dạng delegate dùng kiểu sự kiện, sức mạnh của delegate thì thể hiện rõ nhất ở trong môi trường lập trình này, bạn thường phải mất nhiều thời gian để chuyển đổi dữ liệu giữa các Form, nhưng vấn đề này trở nên vô cùng đơn giản khi bạn sử dụng delegate để xử lý các sự kiện của Windows.
Sau đây là một ví dụ đơn giản dùng delegate để truyền dữ liệu giữa 2 form:
Đầu tiên bạn tạo 2 Form có tên là Form1 và Form2,
– Trên Form1 bạn tạo một Button (Khi click vào thì nó sẽ hiện Form2) và một TextBox để hiển thị dữ liệu từ Form2;
– Trên Form2 bạn chỉ cần tạo một TextBox để ghi dữ liệu cần truyền.

Tiếp đó trong Form2 bạn khai báo một delegate Tranform không có kiểu trả về nhưng có đối số truyền vào là kiểu string; Tiếp theo bạn khai báo một biến Event Tranform để cho Form1 có thể gọi được sự kiện thay đổi từ phía Form2. Cuối cùng bạn chỉ cần gọi delegate trong sự kiện TextChange của TextBox với đối số truyền vào là giá trị của TextBox:

        public delegate void Tranform(string text);
        public event Tranform tranform;
        public Form2()
        {
            InitializeComponent();
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            tranform(textBox2.Text);
        }

Còn ở Form1 Trong sự kiện Click của Button bạn khởi tạo sự kiện Tranform của Form2, sự khởi tạo này có sẽ cập nhật lại giá trị của TextBox trên Form1 mõi khi TextBox trên Form2 thay đổi. Code:

private void button1_Click(object sender, EventArgs e)
        {
          Form2 f = new Form2();
          f.tranform += new Form2.Tranform(f_tranform);
           f.Show();
        }

        void f_tranform(string text)
        {
            textBox1.Text = text;
        }

Khi đó, bạn chú ý hàm f_tranform(string text) thì đối số string text chính là giá trị được truyền qua từ Form2.
Sau khi bạn chạy chương trình thì khi bạn thay đổi giá trị TextBox trên Form2 thì trên Form1 giá trị TextBox cũng thay đổi theo.
Chúng ta đã tìm hiểu sơ qua về delegate, hi vọng các bạn sẽ áp dụng nó vào project của mình. Chúc các bạn thành công!

Categories: Visual C# Tags: ,