Bài viết thứ 4, cũng là bài viết cuối cùng trong series bài viết về delegate này sẽ tiếp tục đào sâu hơn về delegate trong .NET.
More Delegates in .NET

Sau mỗi phiên bản .NET Framework ra đời, tính ứng dụng của delegates càng được mở rộng, cung cấp cho người dùng những giải pháp giúp đơn giản hóa công việc hơn. Bảng dưới đây sẽ liệt kê tên gọi và mô tả về các loại delegate được cung cấp trong phiên bản .NET 3.5 (trong .NET 4.0 còn có nhiều hơn thế này). Để có thể sử dụng delegate, trước hết chúng ta cần phải khai báo chúng. Trong quá trình khai báo, chúng ta quy định signature của function sẽ được đại diện bởi delegate mà chúng ta đang khởi tạo. Nhưng nhờ có những delegate được xây dựng sẵn, chúng ta có thể bỏ qua phần khai báo. Không chỉ cung cấp cho lập trình viên tập hợp delegates rất tiện ích này, .NET còn cung cấp các kiểu Generic delegate (delegate hoạt động với tham số có kiểu dữ liệu bất kì do người dùng chỉ định).




Delegate
Description
Action
Chứa một phương thức không có kiểu trả về và không có tham số.
Action
Tương tự như Action nhưng được phép nhận một tham số
Action>
Nhận được 2 tham số.
Action
Nhận được 3 tham số.
Action
Nhận được 4 tham số.
AppDomainInitializer
Đại diện cho hàm callback, hàm này sẽ được gọi khi application domain được khởi tạo.
AssemblyLoadEventHandler
Represents the method that handles the AssemblyLoad event of an AppDomain.
Đại diện cho phương thức xử lý sự kiện AssemblyLoad của một AppDomain
AsyncCallback
Tham chiếu đến một phương thức sẽ được gọi khi một hoạt động không đồng thời nào đó hoàn tất.
Comparison
Đại diện cho phương thức dùng để so sánh 2 đối tượng cùng kiểu dữ liệu.
ConsoleCancelEventHandler
Đại diện cho phương thức sẽ xử lý sự kiện CancelKeyPress của System.Console.
Converter
Đại diện cho một phương thức dùng để chuyển đổi kiểu của một đối tượng sang kiểu khác.
CrossAppDomainDelegate
Used by DoCallBack for cross-application domain calls.
Sử dụng DoCallBack trong các lời gọi tới các miền thuộc ứng dụng khác
EventHandler
Đại diện cho phương thức sẽ xử lý một sự kiện không có dữ liệu về sự kiện đó.
EventHandler
Đại diện cho một phương thức sẽ xử lý một sự kiện
Func
Tham chiếu đến một phương thức có kiểu trả về là kiểu được quy định bởi tham số TResult, ngoài ra không nhận thêm tham số nào khác.
Func
Tương tự như Func nhưng được phép nhận một tham số.
Func
Có thể nhận được 2 tham số.
Func
Có thể nhận được 3 tham số.
Func
Có thể nhận được 4 tham số.
Predicate
Đại diện cho một phương thức sẽ quy định một tập các yêu cầu, chuẩn mực và xác định liệu một đối tượng nhất định có đạt được yêu cầu này hay không.
ResolveEventHandler
Đại diện cho phương thức xử lý các sự kiện của một AppDomain: TypeResolve, ResourceResolve, và AssemblyResolve
UnhandledExceptionEventHandler
Đại diện cho phương thức sẽ xử lý sự kiện gây ra bởi một ngoại lệ không xác định.
Goal

Trong bài viết này, tôi muốn trình bày những kĩ thuật khác nhau khi sử dụng custom delegates hoặc pre-define delegates. Chúng ta có thể sắp xếp các loại delegates được liệt kê ở bảng trên ra thành các loại sau đây:
1. Generic type function and methods.
  • Action
  • Func
  • Converter
  • Comparision
  • Predicate
2. Event handler – xử lý sự kiện
  • AssemblyLoadEventHandler
  • ConsoleCancelEventHandler
  • EventHandler
  • EventHandler
  • ResolveEventHandler
  • UnhandledExceptionEventHandler
3. Others – các loại khác
  • AppDomainInitializer
  • AsyncCallback (chúng ta đã từng làm quen với delegate này trong phần 2)
  • CrossAppDomainDelegate
Trong bài viết này, tôi sẽ chỉ nói về 3 delegate đầu tiên là Action, Func, Converter. Tôi muốn mô tả cách sử dụng những delegate này bằng nhiều cách khác nhau. Mặc dù compiler sẽ sinh ra những đoạn code tương tự nhau, nhưng đứng từ góc độ lập trình, các kĩ thuật này khác nhau rất nhiều.
Action và Func

Action có thể đại diên cho bất kì phương thức nào return void và có thể nhận tối đa 4 tham số (trong .NET 4.0 là 8). Action: T1 và T2 là các tham số và chúng có kiểu dữ liệu bất kì. Func cũng giống như Action, chỉ khác ở chỗ Func trả về giá trị của một kiểu bất kì. Func: T1, T2 là các tham số có kiểu bất kì và TResult là kiểu trả của giá trị trả về. Như vậy, sẽ không có vấn đề gì nếu tôi chỉ giới thiệu về Action vì Func cũng tương tự như vậy.
Ví dụ sử dụng delegate thông thường

Bên trong namespace của project, tôi khai báo delegate của mình:
public delegate void ShootingHandler(int times);
delegate này return void và nhận một tham số kiểu int. Và bên trong class dưới đây sử dụng biến “shoot” có kiểu của delegate này.
Còn đây là class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class GunClassicDelegate
{
    private ShootingHandler shoot;
    public string Name { get; set; }
    public GunClassicDelegate(string name)
    {
        Name = name;
        switch (Name.ToLower())
        {
            case "automatic gun":
                shoot = new ShootingHandler(ShootAutomatic);
                break;
            case "paint gun":
                shoot = new ShootingHandler(ShootPaint);
                break;
            default:
                shoot = new ShootingHandler(ShootSingle);
                break;
        }
    }
    public void Fire(int times)
    {
        shoot(times);
    }
    private void ShootAutomatic(int times)
    {
        Console.WriteLine("Automatic shooting: ");
        for (int i = 0; i < times; i++)
            Console.Write("Biff...");
        Console.WriteLine();
    }
    private void ShootSingle(int times)
    {
        Console.WriteLine("Single action shooting: ");
        for (int i = 0; i < times; i++)
            Console.WriteLine("Bang");
    }
    private void ShootPaint(int times)
    {
        Console.WriteLine("Splashing paint ");
        for (int i = 0; i < times; i++)
            Console.WriteLine("Bloop");
    }
}

Trong constructor, tùy thuộc vào tên được truyền vào, tôi sẽ truyền vào thể hiện của delegate một trong các hàm sau:
  1. ShootAutomatic
  2. ShootSingle
  3. ShootPaint
Như các bạn thấy, tất cả đều diễn ra hợp lệ bởi các hàm này đều có cùng signature với delegate. Tôi sử dụng một hàm public Fire, trong hàm này delegate sẽ được gọi.
Sử dụng Action delegate do .NET xây dựng

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class GunGenericDelegate
{
    private Action<int> shoot;
    public string Name { get; set; }
    public GunGenericDelegate(string name)
    {
        Name = name;
        switch (Name.ToLower())
        {
            case "automatic gun":
                shoot = ShootAutomatic;
                break;
            case "paint gun":
                shoot = ShootPaint;
                break;
            default:
                shoot = ShootSingle;
                break;
        }
    }
    public void Fire(int times)
    {
        shoot(times);
    }
    private void ShootAutomatic(int times)
    {
        Console.WriteLine("Automatic shooting: ");
        for (int i = 0; i < times; i++)
            Console.Write("Biff...");
        Console.WriteLine();
    }
    private void ShootSingle(int times)
    {
        Console.WriteLine("Single action shooting: ");
        for (int i = 0; i < times; i++)
            Console.WriteLine("Bang");
    }
    private void ShootPaint(int times)
    {
        Console.WriteLine("Splashing paint ");
        for (int i = 0; i < times; i++)
            Console.WriteLine("Bloop");
    }
}