Cấp bậc tác giả:

TRAINING

Delegates và Events trong C#.NET

Được viết bởi QuangIT ngày 12/06/2013 lúc 11:06 AM
Trong bài viết này, bạn sẽ học cách để tạo ra và điều khiển kiểu Delegate cũng như các event C # nhằm hợp lý hoá tiến trình làm việc với kiểu Delegate.
  • 0
  • 10502

Delegates và Events trong C#.NET

Abstract

Trong bài viết này, bạn sẽ học cách để tạo ra và điều khiển kiểu Delegate cũng như các event C # nhằm hợp lý hoá tiến trình làm việc với kiểu Delegate. 
Delegate cung cấp cách để xác định và thực hiện callback. Nó khá linh hoạt cho phép bạn xác định ký tự chính xác của việc gọi, và thông tin đó trở thành một phần của kiểu Delegate. Delegate là kiểu an toàn, hướng đối tượng. 

Tổng quan Delegate:

Delegate là khái niệm trừu tượng của một hoặc nhiều con trỏ hàm (tồn tại trong C + +, giải thích ngoài phạm vi của bài viết này). .NET đã thực thi khái niệm về chức năng gợi ý trong form của Delegate. Với Delegate, bạn có thể xử lý chức năng như dữ liệu. Delegate cho phép chức năng được thông qua các tham số, trả về chức năng như giá trị và được lưu trữ trong mảng. Delegate có các đặc điểm sau:
  • Delegate có nguồn gốc từ lớp System.MulticastDelegate.
  • Chúng có ký hiệu và kiểu trả về. Chức năng được thêm vào cho Delegate phải phù hợp với ký hiệu này.
  • Delegate có thể trỏ đến một trong hai phương thức tĩnh hoặc yêu cầu.
  • Khi đối tượng Delegate được tạo ra, nó có thể tự động gọi các phương thức nó chỉ đến trong runtime.
  • Delegate có thể gọi các phương thức đồng bộ và không đồng bộ.
Delegate có một vài trường hữu ích. Đầu tiên giữ tham chiếu đến đối tượng, và sau đó giữ phương thức con trỏ. Khi gọi Delegate, phương thức instance được gọi tham chiếu. Tuy nhiên, nếu đối tượng tham chiếu là null thì runtime hiểu, nghĩa là phương thức này là phương thức tĩnh. Hơn nữa, cách gọi cú pháp Delegate là chính xác giống như gọi chức năng thông thường. Vì vậy, Delegate là hoàn hảo để thực hiện callback. 

Tại sao cần Delegate

Các hàm API của Windows đã sử dụng thường xuyên của kiểu C con trỏ chức năng để tạo ra các chức năng callback. Sử dụng callback, lập trình viên có thể cấu hình chức năng để báo cáo lại chức năng trong ứng dụng. Vì vậy, mục tiêu của việc sử dụng callback là để xử lý nút click, trình đơn lựa chọn, và các hoạt động di chuyển chuột. Nhưng vấn đề với cách tiếp cận truyền thống này là chức năng callback là kiểu không an toàn. Trong .NET framework, callback vẫn còn có thể sử dụng Delegate với cách tiếp cận hiệu quả hơn. Delegate duy trì ba phần quan trọng của thông tin, như sau:
  • Các thông số của phương thức.
  • Địa chỉ của phương thức callback.
  • Kiểu trả về của phương thức.
Delegate là giải pháp cho tình huống mà bạn muốn vượt qua phương thức quanh các phương thức khác. Bạn đang rất quen với việc truyền dữ liệu với các phương thức thông số mà ý tưởng phương thức truyền qua tham số thay vì dữ liệu, có vẻ hơi lạ. Tuy nhiên, có những trường hợp mà trong đó bạn có phương thức không có gì, ví dụ gọi phương thức khác. Bạn không biết tại thời gian biên dịch phương thức thứ hai này là như thế nào. Thông tin này chỉ có ở runtime vì thế Delegate là thiết bị để vượt qua các biến như vậy. 

Xác định Delegate 

Delegate có thể được định nghĩa làkiểu Delegate. Định nghĩa của nó phải tương tự như chức năng signature. Delegate có thể được định nghĩa trong không gian tên và trong lớp. Delegate không thể được sử dụng như thành viên dữ liệu của lớp hoặc biến địa phương trong phương thức. Các mẫu thử nghiệm xác định kiểu Delegate:
Khả năng tiếp cận Delegate trả lại kiểu delegatename(ParameterList); 
Khái niệm Delegate gần như khai báo phương thức trừu tượng, bạn chỉ cần thay thế các từ khóa trừu tượng với từ khóaDelegate. Sau đây là Delegate hợp lệ: 

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

Khi biên dịch C # gặp dòng này, nó định nghĩa kiểu có nguồn gốc từ MulticastDelegate, cũng thực hiện phương thức có tên Gọi đó có chính xác cùng signature như phương thức mô tả trong delegate. 

public class operation : System.MulticastDelegate
    {
        public double Invoke(int x, int y);
        // Other code
    }

Như bạn thấy sử dụng Ildasm.exe, trình biên dịch lớp định nghĩa tạo ra xác định ba phương thức public như trong hình: 

Delegates1.jpg
Hình 1.1 

Sau khi bạn đã xác định Delegate, bạn có thể tạo thể hiện của nó để bạn có thể sử dụng nó lưu trữ chi tiết phương thức cụ thể. 

Ví dụ chương trình Delegate

Delegate thực thi gây ra thỏa thuận nhầm lẫn khi gặp lần đầu tiên. Do đó, nó là ý tưởng tuyệt vời để có được một sự hiểu biết bằng cách tạo ra chương trình mẫu này như sau: 

using System;

namespace Delegates
{
    // Delegate Definition
    public delegate int operation(int x, int y);
       
    class Program
    {
        // Method that is passes as an Argument
        // It has same signature as Delegates 
        static int Addition(int a, int b)
        {
            return a + b;
        }

        static void Main(string[] args)
        {
            // Delegate instantiation
            operation obj = new operation(Program.Addition);
 
            // output
            Console.WriteLine("Addition is={0}",obj(23,27)); 
            Console.ReadLine();  
        }
    }
}

Ở đây, chúng ta định nghĩa Delegate như kiểu Delegate. Điểm quan trọng cần nhớ là signature tham chiếu chức năng của Delegate phải phù hợp với ký hiệu Delegate như: 

// Delegate Definition
public delegate int operation(int x, int y);

Chú ý định dạng của delegate tuyên bố kiểu toán, nó xác định các đối tượng tính toán cho phép phương thức dùng hai số nguyên và trả lại số nguyên. Khi bạn muốn chèn các phương thức target vào đối tượng delegate đưa ra, chỉ cần qua tên của phương thức đến hàm dựng delegate như sau:

// Delegate instantiation
operation obj = new operation(Program.Addition);

Tại thời điểm này, bạn có thể gọi thành viên chỉ để sử dụng chức năng gọi trực tiếp như 

Console.WriteLine("Addition is={0}",obj(23,27)); 

Cuối cùng, khi delegate không còn cần thiết, thiết lập thể hiện ủy nhiệm đến null . .NET delegate là kiểu an toàn. Do đó, nếu bạn cố gắng để qua delegate phương thức không phù hợp với ký hiệu, .NET sẽ báo cáo một lỗi thời gian biên dịch. 

Mảng delegate

Tạo mảng delegate tương tự như khai báo mảng của bất kỳ kiểu nào. Ví dụ sau đây đã có một vài phương thức tĩnh để thực hiện các hoạt động liên quan đến toán học. Sau đó, bạn sử dụng delegate để gọi các phương thức này.

using System;

namespace Delegates
{
    public class Operation
    {
        public static void Add(int a, int b)
        {
            Console.WriteLine("Addition={0}",a + b);
        }

        public static void Multiple(int a, int b)
        {
            Console.WriteLine("Multiply={0}", a * b);
        }
    } 

class Program
    {
        delegate void DelOp(int x, int y);

        static void Main(string[] args)
        {
            // Delegate instantiation
            DelOp[] obj = 
           {
               new DelOp(Operation.Add),
               new DelOp(Operation.Multiple)
           };
 
            for (int i = 0; i < obj.Length; i++)
            {
                obj[i](2, 5);
                obj[i](8, 5);
                obj[i](4, 6);
            }
            Console.ReadLine();
        }
    }
}

Trong đoạn mã này, bạn khởi tạo mảng của delegates. Mỗi phần tử của mảng được khởi tạo để chỉ một phép toán khác được thực hiện bởi lớp operation. Sau đó, bạn lặp qua mảng, áp dụng mỗi phép toán cho ba giá trị khác nhau. Sau khi biên dịch mã này,  sẽ được như sau: 

Delegates2.jpg
Hình 1.2 

Phương thức Anonymous 

Như tên của nó, là phương pháp không tên. Chúng ngăn chặn tạo ra các phương thức riêng biệt, đặc biệt là khi các chức năng có thể được thực hiện mà không có phương thức sáng tạo mới. Phương thức vô danh cung cấp phương thức sạch hơn và thuận tiện trong khi mã hóa. 

using System;

namespace Delegates
{
    class Program
    {
        // Delegate Definition
        delegate void operation();

        static void Main(string[] args)
        {
            // Delegate instantiation
            operation obj = delegate
            {
                Console.WriteLine("Anonymous method");
            };
            obj();
 
            Console.ReadLine();
        }
    }
}

Các phương thứcvô danh làm giảm sự phức tạp mã, đặc biệt là nơi có một số sự kiện được xác định. Với phương thứcvô danh, mã không thực hiện nhanh hơn. Trình biên dịch vẫn xác định phương thức ngầm. 

Multicast Delegate 

Bạn đã thấy phương thức đơn invocation/call với Delegate. Nếu bạn muốn invoke/call nhiều hơn phương thức, bạn cần phải thực hiện call rõ ràng thông qua Delegate nhiều hơn một lần. Tuy nhiên, nó có thể cho Delegate làm điều đó thông qua multicast Delegate. Multicast Delegate tương tự như container ảo, nơi nhiều chức năng tham chiếu danh sách gọi được lưu trữ. Nó liên tục kêu gọi mỗi phương thứctrong FIFO theo thứ tự. Khi muốn thêm nhiều phương thức đối tượng delegate, bạn chỉ cần sử dụng overloaded + = operator. 

using System;

namespace Delegates
{
    public class Operation
    {
        public static void Add(int a)
        {
            Console.WriteLine("Addition={0}", a + 10);
        }
        public static void Square(int a)
        {
            Console.WriteLine("Multiple={0}",a * a);
        }
    }
    class Program
    {
        delegate void DelOp(int x);
 
        static void Main(string[] args)
        {
            // Delegate instantiation
            DelOp obj = Operation.Add;
            obj += Operation.Square;
 
            obj(2);
            obj(8);
 
            Console.ReadLine();
        }
    }
}

Đoạn mã trên kết hợp hai delegate giữ chức năng Add() và Square(). Ở đây phương thức Add () thực hiện đầu tiên và Square() thực hiện sau. Thứ tự mà các con trỏ chức năng được thêm vào multicast delegate. 
Để loại bỏ những chức năng từ multicast delegate, sử dụng overloaded -= operator cho phép gọi để tự động loại bỏ phương thức từ đối tượng delegate trong danh sách gọi.

// Delegate instantiation
DelOp obj = Operation.Add;
obj -= Operation.Square;

Khi delegate được gọi, Add() được thực hiện nhưng Square() thì không vì chúng ta bỏ đăng ký nó với -= operator từ thông báo runtime. Gọi nhiều phương thức của delegatecó thể dẫn đến tình huống có vấn đề. Nếu một trong những phương thức được viện dẫn bởi delegate ném ngoại lệ, thì lặp lại có thể được hủy bỏ. Có thể tránh kịch bản như vậy bằng cách duyệt danh sách phương thức call riêng. Lớp delegate định nghĩa phương thức GetInvocationListtrả về mảng các đối tượng delegate.

using System;

namespace Delegates
{
    public class Operation
    {
        public static void One()
        {
            Console.WriteLine("one display");
            throw new Exception("Error"); 
        }
        public static void Two()
        {
            Console.WriteLine("Two display");
        }
    }

    class Program
    {
        delegate void DelOp();

        static void Main(string[] args)
        {
            // Delegate instantiation
            DelOp obj = Operation.One;
            obj += Operation.Two;

            Delegate[] del = obj.GetInvocationList();

            foreach (DelOp d in del)
            {
                try
                {
                    d();
                }
                catch (Exception)
                {
                    Console.WriteLine("Error caught");
                }
            }
            Console.ReadLine();
        }
    }
}

Khi bạn chạy ứng dụng, bạn sẽ thấy rằng phiên vẫn tiếp tục với phương thức tiếp theo ngay cả sau khi ngoại lệ được bắt như sau.

Delegates3.jpg
Hình 1.3 

Nguồn bài viết: DOTNET.VN

BÌNH LUẬN BÀI VIẾT

Bài viết mới nhất

LIKE BOX

Bài viết được xem nhiều nhất

HỌC HTML