C# - C Sharp: Delegate

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Tổng quan

Trong .NET Framework, một delegate trỏ tới một hoặc nhiều phương thức. Mỗi khi ta khởi tạo delegate, các phương thức tương ứng sẽ được gọi.

Delegate là đối tượng chứa những tham chiếu tới các phương thức cần được gọi thay vì phải gọi trực tiếp phương thức qua tên của nó. Để sử dụng delegate ta cần gọi một phương thức nào đó và nó được định danh khi thực thi chương trình. Mỗi delegate nói chung cần có một phương thức. Mỗi delegate được coi như một phương thức chung, phương thức chung này trỏ tới các phương thức khác nhau tại những thời điểm khác nhau và tại mỗi thời điểm sẽ gọi một phương thức cụ thể theo yêu cầu của chương trình. Khi ta gọi một delegate thì điều này tương ứng với việc gọi một phương thức được tham chiếu tới.

Để kết hợp delegate với một phương thức cụ thể thì phương thức đó phải có cùng kiểu trả về cũng như số lượng và kiểu tham số với delegate.

Delegate trong C#

Xét hai phương thức là Addition() và Subtract(), phương thức Addition() có hai tham số kiểu int và trả về tổng của hai tham số đó. Tương tự như vậy, phương thức Subtract() cũng có hai tham số kiểu int và trả về hiệu của hai tham số.

Vì cả hai phương thức trên đều có cùng số lượng tham số và kiểu trả về, nên ta tạo một delegate tên Calculation để tham chiếu tới hai phương thức Addition() và Subtract(). Tuy vậy, nếu delegate được gọi để nó trỏ tới phương thức Addition() thì nó phải thực hiện được phép tính tổng hai tham số; và tương tự như thế, nếu ta gọi delegate để nó trỏ tới phương thức Subtract() thì nó phải thực hiện được phép trừ hai tham số.

Delegate trong C# có một số đặc điểm khác biệt với những phương thức thông thường, những đặc điểm này gồm:

· Các phương thức có thể được truyền như là những tham số tới delegate. Ngoài ra, một delegate có thể chấp nhận tham số là một khối lệnh, khối lệnh như vậy sẽ được tham chiếu tới như một phương thức nặc danh.

· Mỗi delegate có thể gọi tới nhiều phương thức cùng một lúc, điều này gọi là multicasting.

· Delegate có thể đóng gói được các phương thức tĩnh.

· Delegate đảm bảo an toàn kiểu (kiểu trả về cũng như kiểu của các tham số) giữa nó và các phương thức được tham chiếu. Điểu này đảm bảo tính bảo mật cũng như độ chính xác cho các dữ liệu khi chúng được truyền tới phương thức được gọi.

Khai báo delegate

Để khai báo delegate trong C# ta dùng từ khóa delegate theo cú pháp như sau:

Bổ_từ_truy_cập delegate Kiểu_trả_về Tên_delegate(Danh_sách_đối_số);

Ví dụ:

public delegate int Calculation(int numOne, int numTwo);

Lưu ý: Nếu bạn khai báo delegate nằm ngoài các lớp thì bạn không thể khai báo thêm delegate có cùng tên và nằm trong cùng namespace.

Tạo thể hiện cho delegate

Sau khi đã khai báo xong delegate thì bạn có thể tạo thể hiện của nó. Cũng giống như những đối tượng khác, khi muốn tạo một thể hiện cho một delegate bạn cần sử dụng từ khóa new, tham số của thể hiện sẽ là phương thức mà delegate muốn tham chiếu tới, và khi thực thi chương trình thì thể hiện của delegate sẽ được dùng để gọi phương tương ứng.

Cú pháp:

Tên_delegate Tên_thể_hiện = new Tên_delegate(Tên_phương_thức);

Ví dụ:

using System;
public delegate int Calculation(int numOne, int numTwo);
class Mathematics
{
  static int Addition(int numOne, int numTwo)
  {
    return (numOne + numTwo);
  }
  static int Subtraction(int numOne, int numTwo)
  {
    return (numOne - numTwo);
  }
  static void Main(string[] args)
  {
    int valOne = 5;
    int valTwo = 23;
    Calculation objCalculation = new Calculation(Addition);
    Console.WriteLine(valOne + " + " + valTwo + " = " + objCalculation(valOne, valTwo));
    objCalculation = new Calculation(Subtraction);
    Console.WriteLine(valOne + " - " + valTwo + " = " + objCalculation(valOne, valTwo));
  }
}

Trong ví dụ trên, delegate Calculation được tạo nằm ngoài lớp Mathematics. Trong phương thức Main() tạo hai đối tượng (thể hiện) của delegate với tham số tương ứng cho mỗi đối tượng là phương thức Addition và phương thức Subtraction. Kiểu tham số của mỗi phương thức và delegate đều cùng kiểu là kiểu int.

Lưu ý: Với phiên bản C# hiện tại, các phương thức không tên gọi là biểu thức 'lambda' được dùng để tạo delegate.

Sử dụng delegate

Ta có thể khai báo delegate nằm ngoài hoặc nằm trong một lớp. Có bốn bước để thực thi một delegate, gồm:

  1. Khai báo delegate.
  2. Tạo phương thức để delegate tham chiếu tới.
  3. Tạo thể hiện (đối tượng) của delegate.
  4. Gọi phương thức thông qua thể hiện của delegate được tạo ở bước 3.

Phương thức nặc danh bản chất là một khối lệnh không có tên, thay vào đó là một delegate. Sử dụng phương thức nặc danh ta sẽ tránh được việc phải tạo tên cho phương thức. Ví dụ:

using System;
class Demo
{
  static void Main(string[] args)
  {
    System.Threading.Thread objThread = new System.Threading.Thread(
      delegate()
      {
        Console.WriteLine("Anonymous Method!");
      }
    );
    objThread.Start();
  }
}

Mô hình Delegate-Event

Mô hình delegate-event là một trong những mô hình lập trình cho phép người dùng tương tác được với máy tính và các thiết bị điều khiển máy tính sử dụng giao diện người dùng đồ họa (Graphical User Interface - GUI). Mô hình này bao gồm:

- Một nguồn sự kiện, nguồn này sẽ là window console trong trường hợp các ứng dụng là dạng console (Console Application).

- Các bộ Listener ('lắng nghe') dùng để nhận các sự kiện từ nguồn sự kiện.

- Một phương tiện (medium) để cung cấp các giao thức cần thiết cho mỗi sự kiện mỗi khi nó được truyền đi.

Theo mô hình trên, mỗi bộ listener có nhiệm vụ phải thực thi một phương tiện ứng với mỗi sự kiện mà nó muốn lắng nghe, khi đó phương tiện sẽ được dùng đến mỗi khi nguồn sự kiện tạo ra một sự kiện, và sự kiện sẽ được thông báo tới bộ listener đã được đăng ký.

Trong C#, mỗi sự kiện là một hành động được tạo ra để kích hoạt phản ứng. Ví dụ, khi nhấn tổ hợp phím Ctrl+Break trên cửa sổ máy chủ dựa trên giao diện điều khiển (console) thì đó là một sự kiện mà sẽ tạo ra hành động kích hoạt máy chủ kết thúc; điều này sẽ gây ra phản ứng kích hoạt dẫn đến thông tin sẽ được lưu vào cơ sở dữ liệu.

Delegate có thể được sử dụng để xử lý các sự kiện; lúc này, delegate sẽ đóng vai trò là tham số và nó có nhiệm vụ mang theo các phương thức được gọi khi xảy ra sự kiện, và những phương thức này được tham chiếu đến như là những bộ xử lý sự kiện.

Sử dụng nhiều delegate trong chương trình

Trong C#, một người dùng có thể gọi nhiều delegate trong cùng một chương trình. Để gọi một delegate ta thông qua tên của nó hoặc kiểu tham số truyền tới delegate. Ví dụ:

using System;
public delegate double CalculateArea(double val);
public delegate double CalculateVolume(double val);
class Cube
{
  static double Area(double val)
  {
    return 6 * (val * val);
  }
  static double Volume(double val)
  {
    return (val * val);
  }
  static void Main(string[] args)
  {
    CalculateArea objCalculateArea = new CalculateArea(Area);
    CalculateVolume objCalculateVolume = new CalculateVolume(Volume);
    Console.WriteLine("Surface Area of Cube: " + objCalculateArea(200.32));
    Console.WriteLine("Volume of Cube: " + objCalculateVolume(20.56));
  }
}

Trong đoạn mã trên, khi tạo các thể hiện của các delegate CalculateArea và CalculateVolume trong hàm Main() thì các tham chiếu của các phương thức Area() và Volume() được truyền như là các tham số tới các delegate tương ứng và các giá trị được truyền tới các thể hiện tương ứng của các delegate.

Multicast Delegate

Một delegate có thể đóng gói các tham chiếu của nhiều phương thức tại cùng một thời điểm. Hay nói cách khác một delegate có thể mang cùng lúc nhiều tham chiếu phương thức. Delegate như vậy gọi là 'Multicast Delegate'. Các phương thức mà multicast delegate tham chiếu (danh sách gọi) sẽ tự động được gọi khi delegate được gọi.

Multicast delegates trong C# được coi là kiểu con của lớp System.MulticastDelegate. Multicast delegate được định nghĩa tượng tự như delegate thông thường, tuy nhiên, kiểu trả về của multicast delegate phải là void. Đó là bởi vì nếu nó trả về một giá trị thì giá trị trả về chính là của phương thức cuối cùng trong danh sách các tham chiếu phương thức, và kiểu của giá trị trả về đó cũng chính là kiểu trả về của delegate; đây là điều không thích hợp. Cho nên delegate luôn luôn có kiểu trả về là void.

Để thêm phương thức vào danh sách gọi của multicast delegate ta cần sử dụng phép '+' hoặc phép '+='. Và ngược lại, để bỏ phương thức khỏi danh sách gọi ta sử dụng phép toán '-' hoặc '-='. Khi một multicast delegate được gọi thì tất cả các phương thức trong danh sách gọi sẽ được gọi tuần tự theo thứ tự phương thức nào được thêm vào multicast delegate trước sẽ được gọi trước. Ví dụ:

using System;
public delegate void Maths(int valOne, int valTwo);
class MathsDemo
{
  static void Addition(int valOne, int valTwo)
  {
    int result = valOne + valTwo;
    Console.WriteLine("Addition: " + valOne + " + " + valTwo + "= " + result);
  }
  static void Subtraction(int valOne, int valTwo)
  {
    int result = valOne - valTwo;
    Console.WriteLine("Subtraction: " + valOne + " - " + valTwo + "= " + result);
  }
  static void Multiplication(int valOne, int valTwo)
  {
    int result = valOne * valTwo;
    Console.WriteLine("Multiplication: " + valOne + " * " + valTwo + "= " +
    result);
  }
  static void Division(int valOne, int valTwo)
  {
    int result = valOne / valTwo;
    Console.WriteLine("Division: " + valOne + " / " + valTwo + "= " + result);
  }
  static void Main(string[] args)
  {
    Maths objMaths = new Maths(Addition);
    objMaths += new Maths(Subtraction);
    objMaths += new Maths(Multiplication);
    objMaths += new Maths(Division);
    if (objMaths != null)
    {
      objMaths(20, 10);
    }
  }
}

Trong ví dụ trên, hàm Main() tạo một thể hiện của delegate Maths tên là objMaths, và sau đó các toán tử '+=' được sử dụng để thêm các phương thức vào danh sách gọi của thể hiện objMaths; như vậy có nghĩa Maths là một multicast delegate.

» Tiếp: Event
« Trước: Con trỏ (Pointer) trong C#
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!