C# Cơ bản .NET Core §1) Cài đặt, chương trình C# đầu tiên §2) Biến, kiểu dữ liệu và nhập/xuất §3) Toán tử số học và gán §4) So sánh, logic và lệnh if, switch §5) Vòng lặp for, while §6) Phương thức - Method §7) Phương thức - Delegate §8) Lớp - Class §9) Kiểu vô danh và dynamic §10) Biểu thức lambda §11) Event §12) Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §13) Lớp lồng nhau - namespace §14) null và nullable §15) Mảng §16) Chuỗi ký tự §17) Tính kế thừa §18) Tính đa hình - abstract - interface §19) Struct và Enum §20) Ngoại lệ Exeption §21) IDisposable - using §22) File cơ bản §23) FileStream §24) Generic §25) Collection - List §26) SortedList §27) Queue / Stack §28) Linkedlist §29) Dictionary - HashSet §30) Phương thức mở rộng §31) ObservableCollection §32) LINQ §33) (Multithreading) async - bất đồng bộ §34) Type §35) Attribute Annotation §36) DI Dependency Injection §37) (Multithreading) Parallel §38) (Networking) HttpClient §39) (Networking) HttpMessageHandler §40) (Networking) HttpListener §41) (Networking) Tcp TcpListenerr/TcpClient §42) (ADO.NET) SqlConnection §43) (ADO.NET) SqlCommand §44) (EF Core) Tổng quan §45) (EF Core) Tạo Model §46) (EF Core) Fluent API §47) (EF Core) Query §48) (EF Core) Scaffold §49) (EF Core) Migration §50) (ASP.NET CORE) Hello World! §51) (ASP.NET CORE) Middleware §52) (ASP.NET CORE) Map - Request - Response §53) (ASP.NET CORE) IServiceCollection - MapWhen §54) (ASP.NET CORE) Session - ISession §55) (ASP.NET CORE) Configuration §56) (ASP.NET CORE MVC) Controller - View
Lập trình C# (C Sharp)

Giới thiệu delegate

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 delegate 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 event trong C# chính là các hàm được gọi thông qua delegate, 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

Delegate được dùng phổ biến khi gán các biểu thức lambda

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 delegate 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 delegate 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 InfoWarning 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 Info, Warning 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 ShowLog, xem đoạn mã đầy đủ sau:

using System;

namespace CS08_Anonymous
{
    class Program
    {
        public delegate void ShowLog(string message);

        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        static void Main(string[] args)
        {
            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 code:

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ụ: if (showLog != null) showLog("Mgs") hoặc gắn gọn hơn showLog?.Invoke("Mgs");

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ử += Nối thêm một phương thức vào delegate, ví dụ delegatevar += method1
  • Toán tử -= : Loại bỏ 1 phương ở cuối (nếu phương thức đó có trong delegate, tính từ cuối) , ví dụ delegatevar -= method1

Ví dụ: sửa ví dụ trên như sau:

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");
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ử +, ví dụ:
delegate_all = d1 + d2

Tải ví dụ: Delegate .NET Core

Tải ví dụ: csharp-example-delegates .NET Framework

Func và Action

FuncAction là hai mẫu delegate định nghĩa sẵn, giúp bạn nhanh chóng tạo ra biến delegate mà không mất công khai báo, như ví dụ trên nếu sử dụng đến Func, Action 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 delegate có kiểu trả về. Để khai báo biến delegate dùng cú pháp như sau:

Func<kiểu_tham_số_1, kiểu_tham_số_2, ..., kiểu_trả_về> var_delegate;

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 delegate tên bien1 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:

Func<int, string, bool> bien1;

Ví dụ:

using System;

namespace CS08_Anonymous
{
    class Program
    {
        static int Sum(int x, int y)
        {
            return x + y;
        }
        static void Main(string[] args)
        {
            Func<int,int,int> tinhtong;         // biến tinhtong phù hợp với các hàm trả về kiểu int, có 2 tham số kiểu int
            tinhtong = Sum;                     // Hàm Sum phù hợp nên có thể gán cho biến

            Console.WriteLine(tinhtong(5,10));  // In ra 15
        }
    }
}

Sử dụng Action

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

Action<kiểu_tham_số_1, kiểu_tham_số_2, ... > var_delegate;

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

Trở lại ví dụ cho hai hàm InfoWarning ở trên, có thể sử dụng ngay đoạn code sau, để có kết quả tương tự:

Action<string> 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");

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:

using System;

namespace CS08_Anonymous
{
    class Program
    { 
        static public void Info(string s)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine(string.Format("Info: {0}", s));
            Console.ResetColor();
        }

        static public void Warning(string s)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(string.Format("Waring: {0}", s));
            Console.ResetColor();
        }

        // Khai báo hàm có tham số là delegate
        static void TinhTong(int a, int b, Action<string> callback)
        {
            int c = a + b;
            // Gọi delegate
            callback("Tổng là: "  + c); // Hoặc callback.Invoke("Tổng là: "  + c);
        }


        static void Main(string[] args)
        {
             TinhTong(5, 7, Info);
             TinhTong(3, 4, Warning);
        }
    }
}
Đăng ký theo dõi ủng hộ kênh