C# Advanced (Series #5) – Delegates

5 min read

  • C# – Anonymous Types
  • C# – Dynamic Types
  • C# – Ternary Operator ?:
  • C# – Generics & Generic Constraints
  • C# – Delegates
  • C# – Func Delegate
  • C# – Action Delegate
  • C# – Anonymous Method
  • C# – Events
  • C# – Extension Method
  • C# – HttpClient

C# Delegates

Điều gì sẽ xảy ra nếu chúng ta muốn truyền một hàm như một tham số? C# xử lý callback functions hoặc event handler như thế nào? Câu trả lời là – delegate.

Delegates là một kiểu dữ liệu tham chiếu định nghĩa method signature. Bạn có thể định nghĩa các biến của kiểu delegate, giống như các kiểu dữ liệu khác, có thể tham chiếu tới bất kỳ phương thức nào có cùng chữ ký với delegate.

Có ba bước liên quan khi làm việc với delegate:

  • Declare a delegate
  • Set a target method
  • Invoke a delegate

delegate có thể được khai báo bằng từ khóa delegate theo sau là function signature, như minh họa dưới đây.

// Delegate Syntax
[access modifier] delegate [return type] [delegate name]([parameters])

Phần sau đây khai báo một delegate có tên là MyDelegate.

// Example: Declare a Delegate
public delegate void MyDelegate(string msg);

Chúng ta đã khai báo một delegate MyDelegate với kiểu trả về void và một tham số kiểu string. Một delegate có thể được khai báo bên ngoài class hoặc bên trong class. Trên thực tế, nó nên được khai báo bên ngoài class.

Sau khi khai báo một delegate, chúng ta cần gán phương thức đích hoặc một biểu thức lambda. Chúng ta có thể thực hiện điều này bằng cách tạo một đối tượng của delegate sử dụng từ khóa new và truyền vào một phương thức có chữ ký phù hợp với delegate signature.

// Example: Set Delegate Target
public delegate void MyDelegate(string msg); // declare a delegate
// set target method
MyDelegate del = new MyDelegate(MethodA);
// or 
MyDelegate del = MethodA; 
// or set lambda expression 
MyDelegate del = (string msg) =>  Console.WriteLine(msg);
// target method
static void MethodA(string message)
{
    Console.WriteLine(message);
}

Bạn có thể đặt target method bằng cách gán trực tiếp một phương thức mà không cần tạo đối tượng delegate

e.g: MyDelegate del = MethodA.

Sau khi thiết lập target method, bạn có thể gọi một delegate bằng phương thức Invoke() hoặc sử dụng toán tử ().

// Example: Invoke a Delegate
del.Invoke("Hello World!");
// or 
del("Hello World!");

Sau đây là một ví dụ đầy đủ về một delegate.

// Example: Delegate
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del = ClassA.MethodA;
        del("Hello World");
        del = ClassB.MethodB;
        del("Hello World");
        del = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
        del("Hello World");
    }
}
class ClassA
{
    static void MethodA(string message)
    {
        Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
    }
}
class ClassB
{
    static void MethodB(string message)
    {
        Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
    }
}

Hình ảnh sau đây minh họa về delegate.

Truyền Delegate làm một tham số

Một phương thức có thể có tham số thuộc delegate type, như hiển thị bên dưới.

// Example: Delegate
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del = ClassA.MethodA;
        InvokeDelegate(del);
        del = ClassB.MethodB;
        InvokeDelegate(del);
        del = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
        InvokeDelegate(del);
    }
    static void InvokeDelegate(MyDelegate del) // MyDelegate type parameter
    {
        del("Hello World");
    }
}
class ClassA
{
    static void MethodA(string message)
    {
        Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
    }
}
class ClassB
{
    static void MethodB(string message)
    {
        Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
    }
}

NOTE:
In .NET, Func and Action types are built-in generic delegates that should be used for most common delegates instead of creating new custom delegates.

Trong .NET, các loại Func và Action là built-in generic delegates nên được sử dụng cho hầu hết các delegates phổ biến thay vì tạo các delegates tùy chỉnh mới.

Multicast Delegate

Delegate có thể trỏ tới nhiều phương thức. Một delegate trỏ đến nhiều phương thức được gọi là multicast delegate. Toán tử “+” hoặc “+=” thêm một hàm vào danh sách cuộc gọi, còn toán tử “-” và “-=” sẽ xóa hàm đó.

// Example: Multicast Delegate
public delegate void MyDelegate(string msg); //declaring a delegate
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del1 = ClassA.MethodA;
        MyDelegate del2 = ClassB.MethodB;
        MyDelegate del = del1 + del2; // combines del1 + del2
        del("Hello World");
        MyDelegate del3 = (string msg) => Console.WriteLine("Called lambda expression: " + msg);
        del += del3; // combines del1 + del2 + del3
        del("Hello World");
        del = del - del2; // removes del2
        del("Hello World");
        del -= del1 // removes del1
        del("Hello World");
    }
}
class ClassA
{
    static void MethodA(string message)
    {
        Console.WriteLine("Called ClassA.MethodA() with parameter: " + message);
    }
}
class ClassB
{
    static void MethodB(string message)
    {
        Console.WriteLine("Called ClassB.MethodB() with parameter: " + message);
    }
}
/*OUTPUT
    After del1 + del2
    Called ClassA.MethodA() with parameter: Hello World
    Called ClassB.MethodB() with parameter: Hello World
    After del1 + del2 + del3
    Called ClassA.MethodA() with parameter: Hello World
    Called ClassB.MethodB() with parameter: Hello World
    Called lambda expression: Hello World
    After del - del2
    Called ClassA.MethodA() with parameter: Hello World
    Called lambda expression: Hello World
    After del1 - del1
    Called lambda expression: Hello World
*/

Các toán tử cộng và trừ luôn hoạt động như một phần của phép gán: del1 += del2; hoàn toàn tương đương với del1 = del1+del2; và tương tự cho phép trừ.

Nếu một delegate trả về một giá trị thì giá trị của phương thức đích được gán cuối cùng sẽ được trả về khi một multicast delegate được gọi.

// Example: Multicast Delegate Returning a Value
public delegate int MyDelegate(); //declaring a delegate
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del1 = ClassA.MethodA;
        MyDelegate del2 = ClassB.MethodB;
        MyDelegate del = del1 + del2; 
        Console.WriteLine(del());// returns 200
    }
}
class ClassA
{
    static int MethodA()
    {
        return 100;
    }
}
class ClassB
{
    static int MethodB()
    {
        return 200;
    }
}

Generic Delegate

Một generic delegate có thể được định nghĩa giống như một delegate nhưng sử dụng generic type parameters hoặc return type. Generic type phải được chỉ định khi bạn đặt phương thức đích.

Ví dụ, hãy xem xét generic delegate sau đây được sử dụng cho các tham số int và string.

// Example: Generic Delegate
public delegate T add<T>(T param1, T param2); // generic delegate
class Program
{
    static void Main(string[] args)
    {
        add<int> sum = Sum;
        Console.WriteLine(sum(10, 20));
        add<string> con = Concat;
        Console.WriteLine(conct("Hello ","World!!"));
    }
    public static int Sum(int val1, int val2)
    {
        return val1 + val2;
    }
    public static string Concat(string str1, string str2)
    {
        return str1 + str2;
    }
}

Delegate cũng được sử dụng để khai báo một Event và một Anonymous Method.

Những điểm cần nhớ:

  • Delegate is the reference type data type that defines the signature.
  • Delegate type variable can refer to any method with the same signature as the delegate.
  • Syntax: [access modifier] delegate [return type] delegate name.
  • A target method’s signature must match with delegate signature.
  • Delegates can be invoke like a normal function or Invoke() method.
  • Multiple methods can be assigned to the delegate using “+” or “+=” operator and removed using “-” or “-=” operator. It is called multicast delegate.
  • If a multicast delegate returns a value then it returns the value from the last assigned target method.
  • Delegate is used to declare an event and anonymous methods in C#.
Avatar photo

Clean Code: Nguyên tắc viết hàm trong lập trình…

Trong quá trình phát triển phần mềm, việc viết mã nguồn dễ đọc, dễ hiểu là yếu tố then chốt để đảm bảo code...
Avatar photo Dat Tran Thanh
3 min read

Clean Code: Nguyên tắc comment trong lập trình

Trong lập trình, code không chỉ là một tập hợp các câu lệnh để máy tính thực thi, mà còn là một hình thức...
Avatar photo Dat Tran Thanh
3 min read

Clean Code: Nguyên tắc xử lý lỗi (Error Handling)

Trong quá trình phát triển phần mềm, việc xử lý lỗi không chỉ là một phần quan trọng mà còn ảnh hưởng trực tiếp...
Avatar photo Dat Tran Thanh
4 min read

One Reply to “C# Advanced (Series #5) – Delegates”

Leave a Reply

Your email address will not be published. Required fields are marked *