Delegate la gi

Một đại biểu chỉ là một hướng đối tượng, quản lý, an toàn và an toàn loại con trỏ hàm trong .NET framework. Một chữ ký đại biểu bao gồm tên, kiểu trả về và đối số được truyền cho nó của nó. Thay vì đi qua dữ liệu, một đại biểu đi một phương pháp để phương pháp khác. Các đại biểu được sử dụng trong nhiều hoàn cảnh, trong đó có callbacks thực hiện và xử lý sự kiện, điểm đề nhập cảnh và nhiều loại chi tiết kỹ thuật phương pháp. Bởi vì một đại biểu không biết lớp của một đối tượng tham chiếu, nó được sử dụng cho gọi nặc danh.

Xem thêm: Thuật ngữ công nghệ A-Z

Giải thích ý nghĩa

What is the Delegate? - Definition

A delegate is an object-oriented, managed, secure and type-safe function pointer in the .NET framework. A delegate signature includes its name, return type and arguments passed to it. Rather than passing data, a delegate passes a method to another method. Delegates are used in many contexts, including implementing callbacks and event handlers, entry thread points and multiple types of method specifications. Because a delegate does not know the class of a referenced object, it is used for anonymous invocation.

Delegate (hàm ủy quyền) là một kiểu dữ liệu, nó dùng để tham chiếu (trỏ đến) đến các hàm (phương thức) có tham số và kiểu trả về phù hợp với khai báo kiểu. Khi dùng đến

ShowLog showLog;
9 bạn có thể gán vào nó một, nhiều hàm (phương thức) có sự tương thích về tham số, kiểu trả về, sau đó dùng nó để gọi hàm (giống con trỏ trong C++), các
static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
0 trong C# chính là các hàm được gọi thông qua
ShowLog showLog;
9, bạn cũng có thể dùng delegate để xây dựng các hàm callback, đặc biệt là các Event

static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
2 được dùng phổ biến khi gán các biểu thức
static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
3

Ví dụ sử dụng delegate

1 Đầu tiên cần khai báo một delegate, khai báo giống như cách khai báo phương thức nhưng có thêm từ khóa

ShowLog showLog;
9 và không có thân phương thức. Ví dụ sau khai báo một delegate có tên là ShowLog

public delegate void ShowLog(string message);

2 Khi đã có ShowLog, nó dùng như một kiểu dữ liệu để khai báo các biến, các biến này có thể gán vào nó các hàm có sự tương đồng về tham số và kiểu trả về với khai báo

ShowLog showLog;
9 ví dụ khai báo biến:

ShowLog showLog;

Thi hành delegate

Sau khi biến delegate được gán hàm vào, có thể dùng biến delegate để thi hành bằng cách gọi:
varDelegate.Invoke(các-tham-số) hoặc varDelegate(các-tham-số)

3 Tạo hai phương thức

static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
6 và
static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
7 có tham số giống với ShowLog, nghĩa là có một tham số kiểu string, trả về void:

static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}

Do

static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
6,
static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
7 có tương đồng về tham số với delegate trên, nên hai hàm này có thể dùng để gán vào biến kiểu
using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}
0, xem đoạn mã đầy đủ sau:

Logs.cs

using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}

Kết quả chạy đoạn, khi gọi hàm

using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}
1:

Waring: Thông báo
Info: Thông báo

Gán nhiều phương thức vào delegate

Khi dùng delegate chạy một phương thức, cần đảm bảo biến delegate đó đã được gán phương thức (biến khác null), có thể bạn kiểm tra trước khi gọi ví dụ:

using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}
2 hoặc gắn gọn hơn
using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}
3

4 Một delegate có thể đưa vào nó nhiều phương thức để một lần gọi thi hành tất cả các phương thức nó chứa

  • Toán tử
    using System;
    
    namespace CS008_Anonymous
    {
        public class Logs
        {
            // Khai báo một delegate
            public delegate void ShowLog(string message);
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Info(string s)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(string.Format("Info: {0}", s));
                Console.ResetColor();
            }
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Warning(string s)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Waring: {0}", s));
                Console.ResetColor();
            }
    
            public static void TestShowLog()
            {
                ShowLog showLog;
    
                showLog = Info;         // showLog gán bằng phương thức Info
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
    
                showLog = Warning;      // showLog gán bằng phương thức Warning
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
            }
        }
    }
    
    4 Nối thêm một phương thức vào delegate, ví dụ
    using System;
    
    namespace CS008_Anonymous
    {
        public class Logs
        {
            // Khai báo một delegate
            public delegate void ShowLog(string message);
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Info(string s)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(string.Format("Info: {0}", s));
                Console.ResetColor();
            }
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Warning(string s)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Waring: {0}", s));
                Console.ResetColor();
            }
    
            public static void TestShowLog()
            {
                ShowLog showLog;
    
                showLog = Info;         // showLog gán bằng phương thức Info
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
    
                showLog = Warning;      // showLog gán bằng phương thức Warning
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
            }
        }
    }
    
    5
  • Toán tử
    using System;
    
    namespace CS008_Anonymous
    {
        public class Logs
        {
            // Khai báo một delegate
            public delegate void ShowLog(string message);
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Info(string s)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(string.Format("Info: {0}", s));
                Console.ResetColor();
            }
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Warning(string s)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Waring: {0}", s));
                Console.ResetColor();
            }
    
            public static void TestShowLog()
            {
                ShowLog showLog;
    
                showLog = Info;         // showLog gán bằng phương thức Info
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
    
                showLog = Warning;      // showLog gán bằng phương thức Warning
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
            }
        }
    }
    
    6 : Loại bỏ 1 phương ở cuối (nếu phương thức đó có trong delegate, tính từ cuối) , ví dụ
    using System;
    
    namespace CS008_Anonymous
    {
        public class Logs
        {
            // Khai báo một delegate
            public delegate void ShowLog(string message);
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Info(string s)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(string.Format("Info: {0}", s));
                Console.ResetColor();
            }
    
            // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
            static public void Warning(string s)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Waring: {0}", s));
                Console.ResetColor();
            }
    
            public static void TestShowLog()
            {
                ShowLog showLog;
    
                showLog = Info;         // showLog gán bằng phương thức Info
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
    
                showLog = Warning;      // showLog gán bằng phương thức Warning
                showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
            }
        }
    }
    
    7

Ví dụ:

public static void TestShowLogMulti()
{
    ShowLog showLog;

    showLog = null;
    showLog += Warning;         // Nối thêm Warning vào delegate
    showLog += Info;            // Nối thêm Info vào delegate
    showLog += Warning;         // Nối thêm Warning vào delegate

    //Một lần gọi thi hành tất cả các phương thức trong chuỗi delegate
    showLog("TestLog");         //Hoặc an toàn: showLog?.Invoke("TestLog");
}

Gọi phương thức

using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}
8 thì kết quả:

Waring: TestLog
Info: TestLog
Waring: TestLog

5 Ngoài cách gán cho delegate một hàm có tên cụ thể như trên, bạn cũng có thể gán một phương thức Anonymou, ví dụ:

showLog += (x) => Console.WriteLine(string.Format("===>{0}<===", x));

6 Các delegate cùng kiểu có thể kết hợp lại với nhau bằng toán tử

using System;

namespace CS008_Anonymous
{
    public class Logs
    {
        // Khai báo một delegate
        public delegate void ShowLog(string message);

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        // Phương thức tương đồng với ShowLog (tham số, kiểu trả về)
        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        public static void TestShowLog()
        {
            ShowLog showLog;

            showLog = Info;         // showLog gán bằng phương thức Info
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info

            showLog = Warning;      // showLog gán bằng phương thức Warning
            showLog("Thông báo");   // Thi hành delegate chính là thi hành Info
        }
    }
}
9, ví dụ:

// Cộng nhiều Delegate
public static void TestShowLogPlus()
{
    ShowLog showLog1 = (x)=> {Console.WriteLine($"-----{x}-----");};
    ShowLog showLog2 = Warning;
    ShowLog showLog3 = Info;

    var all = showLog1 + showLog2 + showLog3 + showLog1;

    all("Xin Chào");
}

Gọi phương thức

Waring: Thông báo
Info: Thông báo
0 kết quả là:

-----Xin Chào-----
Waring: Xin Chào
Info: Xin Chào
-----Xin Chào-----

Func và Action

Waring: Thông báo
Info: Thông báo
1 và
Waring: Thông báo
Info: Thông báo
2 là hai mẫu delegate định nghĩa sẵn, giúp bạn nhanh chóng tạo ra biến kiểu delegate mà không mất công khai báo, xem lại ví dụ trên nếu sử dụng đến
Waring: Thông báo
Info: Thông báo
1,
Waring: Thông báo
Info: Thông báo
2 thì không cần có dòng khai báo:

public delegate void ShowLog(string message);

Sử dụng Func

Func là mẫu

ShowLog showLog;
9 có kiểu trả về. Để khai báo biến delegate dùng cú pháp như sau:

ShowLog showLog;
1

Kiểu cuối cùng trong khai báo Func là kiểu trả về của hàm, có thể thiếu tham số nhưng không được thiếu kiểu trả về

Ví dụ muốn có biến

ShowLog showLog;
9 tên
Waring: Thông báo
Info: Thông báo
7 tương đương với hàm có 2 tham số, tham số 1 kiểu int, tham số 2 kiểu string, và hàm trả về kiểu bool thì tạo biến đó như sau:

ShowLog showLog;
2

Khai báo trên nếu bạn dùng cách thông thường tương ứng với:

ShowLog showLog;
3

Ví dụ:

ShowLog showLog;
4

Khi gọi phương thức

Waring: Thông báo
Info: Thông báo
8 kết quả:

ShowLog showLog;
5

Sử dụng Action

Waring: Thông báo
Info: Thông báo
2 tương tự như
Waring: Thông báo
Info: Thông báo
1, điều khác duy nhất là nó không có kiểu trả về, khai báo cơ bản như sau:

ShowLog showLog;
6

Nghĩa là biến kiểu Action có thể gán bằng các hàm có kiểu trả về

public static void TestShowLogMulti()
{
    ShowLog showLog;

    showLog = null;
    showLog += Warning;         // Nối thêm Warning vào delegate
    showLog += Info;            // Nối thêm Info vào delegate
    showLog += Warning;         // Nối thêm Warning vào delegate

    //Một lần gọi thi hành tất cả các phương thức trong chuỗi delegate
    showLog("TestLog");         //Hoặc an toàn: showLog?.Invoke("TestLog");
}
1

Trở lại ví dụ cho hai hàm

static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
6 và
static public void Info(string s)
{
    // ...
}

static public void Warning(string s)
{
    // ...
}
7 ở trên, có thể sử dụng ngay đoạn code sau, để có kết quả tương tự:

ShowLog showLog;
7

Sử dụng Delegate làm tham số hàm

Có thể sử dụng delegate làm tham số của phương thức, nó có vai trò như những hàm callback linh hoạt. Xem ví dụ sau: