Delegate trong c# là gì

Skip to main content

This browser is no longer supported.

Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.

Delegates (C# Programming Guide)

  • Article
  • 01/12/2022
  • 2 minutes to read

In this article

A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.

Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates. You create a custom method, and a class such as a windows control can call your method when a certain event occurs. The following example shows a delegate declaration:

public delegate int PerformCalculation(int x, int y);

Any method from any accessible class or struct that matches the delegate type can be assigned to the delegate. The method can be either static or an instance method. This flexibility means you can programmatically change method calls, or plug new code into existing classes.

Note

In the context of method overloading, the signature of a method does not include the return value. But in the context of delegates, the signature does include the return value. In other words, a method must have the same return type as the delegate.

This ability to refer to a method as a parameter makes delegates ideal for defining callback methods. You can write a method that compares two objects in your application. That method can be used in a delegate for a sort algorithm. Because the comparison code is separate from the library, the sort method can be more general.

Function pointers were added to C# 9 for similar scenarios, where you need more control over the calling convention. The code associated with a delegate is invoked using a virtual method added to a delegate type. Using function pointers, you can specify different conventions.

Delegates Overview

Delegates have the following properties:

  • Delegates are similar to C++ function pointers, but delegates are fully object-oriented, and unlike C++ pointers to member functions, delegates encapsulate both an object instance and a method.
  • Delegates allow methods to be passed as parameters.
  • Delegates can be used to define callback methods.
  • Delegates can be chained together; for example, multiple methods can be called on a single event.
  • Methods don't have to match the delegate type exactly. For more information, see Using Variance in Delegates.
  • Lambda expressions are a more concise way of writing inline code blocks. Lambda expressions (in certain contexts) are compiled to delegate types. For more information about lambda expressions, see Lambda expressions.

In This Section

  • Using Delegates
  • When to Use Delegates Instead of Interfaces (C# Programming Guide)
  • Delegates with Named vs. Anonymous Methods
  • Using Variance in Delegates
  • How to combine delegates (Multicast Delegates)
  • How to declare, instantiate, and use a delegate

C# Language Specification

For more information, see Delegates in the C# Language Specification. The language specification is the definitive source for C# syntax and usage.

  • Delegates, Events, and Lambda Expressions in C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers
  • Delegates and Events in Learning C# 3.0: Fundamentals of C# 3.0

See also

  • Delegate
  • C# Programming Guide
  • Events

Feedback

Submit and view feedback for

  • Trung Nguyen
  • 06/04/2020

  • 11 min read

Một phương thức có thể có một hoặc nhiều tham số có kiểu dữ liệu khác nhau, nhưng nếu bạn muốn truyền một phương thức làm tham số thì sao? Làm thế nào để C# xử lý các chức năng gọi lại (callback) hoặc xử lý sự kiện? Câu trả lời là sử dụng delegate.

Delegate trong C#

Một delegate giống như một con trỏ đến một phương thức (gọi là con trỏ hàm trong C và C++). Delegate là kiểu tham chiếu và nó chứa tham chiếu tới một phương thức. Tất cả các delegate đều bắt nguồn từ lớp System.Delegate.

Một delegate có thể được khai báo bằng cách sử dụng từ khóa delegate, theo sau là chữ ký phương thức như dưới đây.

<access modifier> delegate <return type> <delegate_name>(<parameters>)
Chữ ký phương thức gồm tên phương thức, số lượng và kiểu dữ liệu của các tham số nhưng không bao gồm kiểu dữ liệu trả về. Tuy nhiên đối với delegate thì chứ ký phương thức bao gồm cả kiểu dữ liệu trả về.

Ví dụ sau khai báo một delegate Print.

public delegate void Print(int value);

Delegate Print có thể được sử dụng để trỏ đến bất kỳ phương thức nào có cùng kiểu dữ liệu trả về và số lượng/kiểu dữ liệu của tham số được khai báo với Print. Ví dụ sau minh họa cách sử dụng delegate Print.

class Program { // declare delegate public delegate void Print(int value); static void Main(string[] args) { // Print delegate points to PrintNumber Print printDel = PrintNumber; // or // Print printDel = new Print(PrintNumber); printDel(100000); printDel(200); // Print delegate points to PrintMoney printDel = PrintMoney; printDel(10000); printDel(200); } public static void PrintNumber(int num) { Console.WriteLine("Number: {0,-12:N0}",num); } public static void PrintMoney(int money) { Console.WriteLine("Money: {0:C}", money); } }

Đây là kết quả khi biên dịch và chạy chương trình:

Number: 10,000 Number: 200 Money: $ 10,000.00 Money: $ 200.00

Trong ví dụ trên, chúng tôi đã khai báo delegate Print chấp nhận tham số kiểu int và trả về kiểu void. Trong phương thức Main(), một biến printDel kiểu Print được khai báo và gán tên phương thức PrintNumber.

Bây giờ, mỗi khi gọi thực thi biến printDel sẽ gọi tới phương thức PrintNumber. Tương tự, nếu biến printDel được gán cho phương thức PrintMoney, thì nó sẽ gọi phương thức PrintMoney.

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

Delegate trong c# là gì

Tùy chọn, một đối tượng delegate có thể được khởi tạo bằng từ khóa new và chỉ định tên phương thức, như ví dụ dưới đây:

Print printDel = new Print(PrintNumber);

Gọi delegate

Delegate có thể được gọi như một phương thức vì nó là một tham chiếu đến một phương thức.

Khi gọi một delegate sẽ gọi tới phương thức mà delegate tham chiếu tới. Delegate có thể được gọi bằng hai cách: sử dụng toán tử () hoặc sử dụng phương thức ủy nhiệm Invoke() như dưới đây:

Print printDel = PrintNumber; printDel.Invoke(10000); //or printDel(10000);

Đây là kết quả khi biên dịch và chạy chương trình:

Number: 10000 Number: 10000

Truyền delegate như một tham số

Một phương thức có thể có một tham số kiểu delegate. Phương thức có thể gọi thực thi tham số delegate này. Ví dụ sau minh họa truyền delegate như một tham số của phương thức:

public static void PrintHelper(Print delegateFunc, int numToPrint) { delegateFunc(numToPrint); }

Trong ví dụ trên, phương thức PrintHelper có một tham số delegateFunc kiểu Print là một delegate. Nó gọi thực thi delegate này: delegateFunc(numToPrint).

Ví dụ sau đây cho thấy cách sử dụng phương thức PrintHelper:

class Program { public delegate void Print(int value); static void Main(string[] args) { PrintHelper(PrintNumber, 10000); PrintHelper(PrintMoney, 10000); } public static void PrintHelper(Print delegateFunc, int numToPrint) { delegateFunc(numToPrint); } public static void PrintNumber(int num) { Console.WriteLine("Number: {0,-12:N0}",num); } public static void PrintMoney(int money) { Console.WriteLine("Money: {0:C}", money); } }

Đây là kết quả khi biên dịch và chạy chương trình:

Number: 10,000 Money: $ 10,000.00

Multicast delegate

Delegate có thể tham chiếu tới nhiều phương thức một lúc. Một delegate tham chiếu tới nhiều phương thức được gọi là multicast delegate. Toán tử + thêm một phương thức vào đối tượng delegate và toán tử - loại bỏ một phương thức hiện có ra khỏi một đối tượng delegate.

Ví dụ dưới đây sẽ minh họa về multicast delegate:

public delegate void Print(int value); static void Main(string[] args) { Print printDel = PrintNumber; printDel += PrintHexadecimal; printDel += PrintMoney; printDel(1000); printDel -= PrintHexadecimal; printDel(2000); } public static void PrintNumber(int num) { Console.WriteLine("Number: {0,-12:N0}",num); } public static void PrintMoney(int money) { Console.WriteLine("Money: {0:C}", money); } public static void PrintHexadecimal(int dec) { Console.WriteLine("Hexadecimal: {0:X}", dec); }

Đây là kết quả khi biên dịch và chạy chương trình:

Number: 1,000 Hexadecimal: 3EB Money: $ 1,000.00 Number: 2,000 Money: $2,000.00

Như bạn có thể thấy trong ví dụ trên, delegate Print trở thành một multicast delegate vì nó tham chiếu đến ba phương thức: PrintNumber, PrintMoney và PrintHexadecimal. Vì vậy, khi gọi thực thi printDel sẽ gọi tuần tự tất cả các phương thức trên.

Delegate cũng được sử dụng với Event, anonymous method (phương thức ẩn danh), delegate Func, delegate Action.

Những điểm cần nhớ về delegate trong C#

  • Delegate là một con trỏ phương thức (nó tham chiếu đến phương thức). Nó là kiểu dữ liệu tham chiếu.
  • Một phương thức được gán cho delegate phải có cùng chữ ký với delegate.
  • Delegate có thể được gọi như một phương thức bình thường sử dụng toán tử () hoặc sử dụng phương thức Invoke().
  • Nhiều phương thức có thể được gán cho một delegate bằng toán tử +. Nó được gọi là multicast delegate.

Delegate Func trong C#

C# 3.0 có các kiểu generic delegate tích hợp sẵn như Func và Action do đó bạn không cần phải định nghĩa các delegate tùy chỉnh như ở trên.

Func là một generic delegate thuộc namespace System. Nó không có hoặc có nhiều tham số đầu vào và một tham số out. Tham số cuối cùng được coi là một tham số out.

Ví dụ: delegate Func có một tham số đầu vào và một tham số out được định nghĩa trong namespace System như dưới đây:

namespace System { public delegate TResult Func<in T, out TResult>(T arg); }

Tham số cuối cùng trong ngoặc <> được xem là kiểu trả về và các tham số còn lại được coi là loại tham số đầu vào như trong hình dưới đây.

Delegate trong c# là gì

Delegate Func có hai tham số đầu vào và một tham số out sẽ được trình bày như dưới đây.

Delegate trong c# là gì

Biến sum dưới đây có kiểu delegate Func với hai tham số đầu vào của kiểu int và trả về giá trị của kiểu int:

Func<int, int, int> sum;

Bạn có thể gán bất kỳ phương thức nào có hai tham số int và trả về kiểu int  cho biến sum ở trên. Hãy xem ví dụ sau:

class Program { static int Sum(int x, int y) { return x + y; } static void Main(string[] args) { Func<int,int, int> add = Sum; int result = add(10, 10); Console.WriteLine(result); } }

Đây là kết quả khi biên dịch và chạy chương trình:

20

Một kiểu delegate Func có thể không có hoặc có đến 16 tham số đầu vào của các kiểu dữ liệu khác nhau. Tuy nhiên, nó phải bao gồm một tham số out cho kết quả. Ví dụ, delegate Func sau đây không có bất kỳ tham số đầu vào nào, nó chỉ có một tham số out.

Func<int> getRandomNumber;

Delegate Func với phương thức ẩn danh trong C#

Bạn có thể chỉ định một phương thức ẩn danh cho delegate Func bằng cách sử dụng từ khóa delegate.

Chúng ta sửa đổi lại ví dụ trên một chút, sử dụng phương thức ẩn danh thay thế cho phương thức Sum:

class Program { static void Main(string[] args) { Func<int,int, int> add = delegate(int x, int y) { return x + y; }; int result = add(10, 10); Console.WriteLine(result); } }

Đây là kết quả khi biên dịch và chạy chương trình:

20

Delegate Func với biểu thức Lambda trong C#

Một delegate Func cũng có thể được sử dụng với biểu thức lambda, chúng ta lại tiếp tục sửa ví dụ trên như sau:

class Program { static void Main(string[] args) { Func<int,int, int> add = (x, y) => x + y; int result = add(10, 10); Console.WriteLine(result); } }

Đây là kết quả khi biên dịch và chạy chương trình:

20

Những điểm cần nhớ về delegate Func trong C#

  • Func là kiểu delegate được tích hợp sẵn trong C#.
  • Delegate Func phải trả về một giá trị.
  • Delegate Func có thể không có hoặc có đến 16 tham số đầu vào.
  • Delegate Func không cho phép tham số ref và out.
  • Delegate Func có thể được sử dụng với một phương thức ẩn danh hoặc biểu thức lambda .

Delegate Action trong C#

Action cũng là một loại delegate được định nghĩa trong namespace System. Delegate Action cũng tương tự như delegate Func ngoại trừ delegate Action không trả về giá trị. Nói cách khác, một delegate Action có thể được sử dụng với một phương thức có kiểu trả về là void.

Ví dụ minh họa sử dụng delegate Action:

static void ConsolePrint(int i) { Console.WriteLine(i); } static void Main(string[] args) { Action<int> print = ConsolePrint; print(10); }

Đây là kết quả khi biên dịch và chạy chương trình:

10

Bạn có thể khởi tạo một delegate Action bằng cách sử dụng từ khóa new hoặc bằng cách chỉ định trực tiếp một phương thức như dưới đây:

Action<int> printActionDel = ConsolePrint; //Or Action<int> printActionDel = new Action<int>(ConsolePrint);

Một đại biểu hành động có thể mất tới 16 tham số đầu vào thuộc các loại khác nhau.

Delegate Action với phương thức ẩn danh trong C#

Một phương thức ẩn danh cũng có thể được chỉ định cho một delegate Action:

static void Main(string[] args) { Action<int> print = delegate(int i) { Console.WriteLine(i); }; print(10); }

Đây là kết quả khi biên dịch và chạy chương trình:

10

Delegate Action với biểu thức Lambda trong C#

Biểu thức Lambda cũng có thể được sử dụng với delegate Action:

static void Main(string[] args) { Action<int> print = i => Console.WriteLine(i); print(10); }

Đây là kết quả khi biên dịch và chạy chương trình:

10

Do đó, bạn có thể sử dụng bất kỳ phương thức nào không trả về giá trị cho delegate Action.

Những điểm cần nhớ về delegate Action trong C#

  • Delegate Action cũng giống như delegate Func ngoại trừ việc nó không trả về giá trị. Kiểu trả về phải là void.
  • Delegate Action có thể không có hoặc có đến 16 tham số đầu vào.
  • Delegate Action có thể được sử dụng với các phương thức ẩn danh hoặc biểu thức Lambda.

Ưu điểm của delegate Func và Action

  • Dễ dàng và nhanh chóng để định nghĩa các delegate.
  • Làm cho mã ngắn gọn và dễ đọc.
  • Kiểu dữ liệu tương thích trong suốt ứng dụng.

Delegate Predicate trong C#

Predicate cũng là một delegate như delegate Func và Action. Nó đại diện cho một phương thức chứa một tập hợp các tiêu chí và kiểm tra xem tham số đã truyền có đáp ứng các tiêu chí đó hay không. Một phương thức được gán cho delegate Predicate phải có một tham số đầu vào và trả về kiểu boolean.

Delegate Predicate được định nghĩa trong namespace System.

Cũng giống như các loại delegate khác, delegate Predicate cũng có thể được sử dụng với bất kỳ phương thức, phương thức ẩn danh hoặc biểu thức lambda nào.

static bool IsUpperCase(string str) { return str.Equals(str.ToUpper()); } static void Main(string[] args) { Predicate<string> isUpper = IsUpperCase; bool result = isUpper("hello world!!"); Console.WriteLine(result); }

Đây là kết quả khi biên dịch và chạy chương trình:

False

Delegate Predicate với phương thức ẩn danh trong C#

Một phương thức ẩn danh cũng có thể được gán cho loại đại biểu Dự đoán như dưới đây.

static void Main(string[] args) { Predicate<string> isUpper = delegate(string s) { return s.Equals(s.ToUpper()); }; bool result = isUpper("hello world!!"); }

Đây là kết quả khi biên dịch và chạy chương trình:

False

Delegate Predicate với biểu thức Lambda trong C#

Biểu thức lambda cũng có thể được gán cho kiểu delegate Predicate như dưới đây.

static void Main(string[] args) { Predicate<string> isUpper = s => s.Equals(s.ToUpper()); bool result = isUpper("hello world!!"); }

Đây là kết quả khi biên dịch và chạy chương trình:

False

Những điểm cần nhớ về delegate Predicate trong C#:

  • Delegate Predicate có một tham số đầu vào và kiểu trả về boolean.
  • Phương thức ẩn danh và biểu thức Lambda có thể được gán cho delegate Predicate.

Nếu Comdy hữu ích và giúp bạn tiết kiệm thời gian

Bạn có thể vui lòng tắt trình chặn quảng cáo ❤️ để hỗ trợ chúng tôi duy trì hoạt động của trang web.

Lập Trình C# • Lập Trình C# Cơ Bản