Delegate và Event trong Csharp

Khái niệm delegate được hiểu như là một con trỏ hàm (method). Thực tế là một method nó cũng có 1 vùng nhớ xác định trên Ram và khi biết được địa chỉ của vùng nhớ này thì mình có thể gọi method thực hiện, bình thường mình gọi method thông qua đối tượng (instance) hoặc tên class (nếu là method static) và tên method. Như vậy một delegate được hiểu nôm na là một kiểu dùng để lưu trữ 1 hay nhiều địa chỉ method mà những method này phải cùng prototype (gồm kiểu trả về và danh sách các tham số). Khi ta có một biến delegate đang nắm giữ danh sách các method (có cùng prototype với nó) thì chỉ cần khởi động biến này tất cả các danh sách method đó sẽ được thực hiện lần lượt mà ta không cần quan tâm đến tên method đó nữa.

Delegate rất có ý nghĩa khi kết hợp với event, như bác sangcn đã đề cập thì event là một thể hiện đặc biệt của delegate. Theo khái niệm thì event là một thông điệp được gửi tới những đối tượng đã đăng ký trước đó để thực hiện hành động nào đó kèm theo khi thông điệp đó được gửi tới (nghĩa là sự kiện đó xảy ra). Ví dụ, khi chúng ta click chuột vào 1 nút (button) nào đó trên một form (cửa sổ ứng dụng), nghĩa là lúc này đối tượng nút sẽ truyền một thông điệp (phát ra sự kiện nhấn chuột) cho đối tượng form để gọi tới method mà form này đã đăng ký nhận thông điệp khi sự kiện nhấn chuột xảy ra.

Một ứng dụng cụ thể để hiểu mục đích sử dụng delegate event đó là chúng ta viết một class clock (đồng hồ), và một yêu cầu rằng khi người ta sử dụng đối tượng clock này thì muốn nhận một thông điệp (sự kiện) EndTime (hết giờ) để thực hiện một hành động gì đó kèm theo sự kiện này. Ví dụ ta viết một chương trình game đoán chữ và có giới hạn thời gian cho người chơi là 10 giây, hết thời gian này thì chương trình sẽ thông báo "Time over" chẳng hạn. Như vậy, ta sẽ cần ít nhất 2 class là Game và Clock. Chúng ta hãy xem mã nguồn để thể hiện ví dụ này.

public class Clock
{
    private int _second;
    // Định nghĩa một delegate để trỏ vào những method có kiểu không đối số, không kiểu trả về
    public delegate void TimeOver();
    // Khai báo 1 event thuộc kiểu delegate trên
    public event TimeOver EndTime;
    public Clock(int second)
    {
        _second = second;
    }
    public int Second
    {
        get { return _second; }
        set { _second = value; }
    }
    /// 
    /// Method đếm lùi thời gian cho đến khi _second = 0 thì kết thúc và báo lên sự kiện EndTime
    /// 
    public void Timedown()
    {
        do
        {
            _second--;
            Thread.Sleep(1000);
        }
        while (_second > 0);
        // trước khi gọi event hoặc delegate thì cần kiểm tra biến có null không (nghĩa là có chứa địa chỉ
        // của method nào không) nếu khác null (có chứa 1 ít nhât 1 method) thì mới gọi.
        if (EndTime != null)
            EndTime(); // gọi thực hiện các method đã đăng ký sự kiện.
    }
}
class Game
{
    /// 
    /// Method dùng để thực hiện hành động kèm theo khi sự kiện EndTime (delegate TimeOver) xảy ra
    /// 
    public void GameOver()
    {
        Console.WriteLine("Game over");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Clock c = new Clock(10);
        Game g = new Game();
        // Đăng ký method thực hiện hành động kèm theo khi có sự kiện EndTime xảy ra
        c.EndTime += new Clock.TimeOver(g.GameOver);
        ThreadStart ts = new ThreadStart(c.Timedown);
        Thread ChildThread = new Thread(ts);
        ChildThread.Start();
        Console.WriteLine("Waiting about 10 second...");
    }
}

Chủ đề này là một chủ đề lớn và rất hay vì thế sẽ có video để chúng ta tìm hiểu sâu hơn nữa. Hy vọng bạn cũng phần nào nắm được. Tôi gửi link download mã nguồn cho ví dụ trên để bạn tiện tham khảo.

DemoEvent.rar (23,46 kb)

Nguồn: http://www.hoctinhoctructuyen.com/Questions?page=3&TypeSearch=-1

Làm thế nào để Declare, Instantiate, và sử dụng là một Delegate

Trong C# 1.0 và trở về sau, các delegate có thể được kê khai như trong ví dụ sau.

// Declare a delegate.
delegate void Del(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
          Console.WriteLine("Notification received for: {0}", name);
}

// Create an instance of the delegate.
Del del1 = new Del(Notify);



C# 2.0 cung cấp một cách đơn giản để viết delegate trước đó, như trong ví dụ sau.

// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;

Trong C# 2.0 và sau, nó cũng có thể sử dụng một method anonymous để khai báo và khởi tạo là một delegate, như trong ví dụ sau.

// Instantiate Del by using an anonymous method.
Del del3 = delegate(string name) { Console.WriteLine("Notification received for: {0}", name); };



Trong C# 3.0 và sau, các delegate cũng có thể được khai báo và khởi tạo bằng cách sử dụng là một biểu thức lambda, như trong ví dụ sau.

// Instantiate Del by using a lambda expression.
Del del4 = name => { Console.WriteLine("Notification received for: {0}", name); };



Việc sử dụng các các delegate phát huy tốt chức năng tách giữa các cơ sở dữ liệu mã hiệu sách và các khách hàng. Mã khách hàng không có kiến thức về cách các cuốn sách được lưu trữ hoặc làm thế nào mã hiệu sách tìm thấy cuốn sách bìa mềm. Các mã hiệu sách không có kiến thức về những gì xử lý được thực hiện trên những cuốn sách bìa mềm sau khi nó tìm thấy chúng.

// A set of classes for handling a bookstore:
namespace Bookstore
{
       using System.Collections;

       // Describes a book in the book list:
       public struct Book
       {
               public string Title; // Title of the book.
               public string Author; // Author of the book.
               public decimal Price; // Price of the book.
               public bool Paperback; // Is it paperback?

               public Book(string title, string author, decimal price, bool paperBack)
               {
                      Title = title;
                      Author = author;
                      Price = price;
                      Paperback = paperBack;
               }
        }

        // Declare a delegate type for processing a book:
        public delegate void ProcessBookDelegate(Book book);

        // Maintains a book database.
        public class BookDB
        {
               // List of all books in the database:
               ArrayList list = new ArrayList();

               // Add a book to the database:
               public void AddBook(string title, string author, decimal price, bool paperBack)
               {
                      list.Add(new Book(title, author, price, paperBack));
               }

               // Call a passed-in delegate on each paperback book to process it:
               public void ProcessPaperbackBooks(ProcessBookDelegate processBook)
               {
                      foreach (Book b in list)
                      {
                             if (b.Paperback)
                                   // Calling the delegate:
                                   processBook(b);
                      }
               }
        }
}

// Using the Bookstore classes:
namespace BookTestClient
{
       using Bookstore;

       // Class to total and average prices of books:
       class PriceTotaller
       {
               int countBooks = 0;
               decimal priceBooks = 0.0m;

               internal void AddBookToTotal(Book book)
               {
                       countBooks += 1;
                       priceBooks += book.Price;
               }

               internal decimal AveragePrice()
               {
                       return priceBooks / countBooks;
               }
        }

         // Cla ss to test the book database:
         class TestBookDB
         {
                // Print the title of the book.
                static void PrintTitle(Book b)
                {
                         System.Console.WriteLine(" {0}", b.Title);
                }

                // Execution starts here.
                static void Main()
                {
                           BookDB bookDB = new BookDB();

                           // Initialize the database with some books:
                           AddBooks(bookDB);
                           // Print all the titles of paperbacks:
                           System.Console.WriteLine("Paperback Book Titles:");

                           // Create a new delegate object associated with the static
                           // method Test.PrintTitle:
                           bookDB.ProcessPaperbackBooks(PrintTitle);
                           // Get the average price of a paperback by using
                           // a PriceTotaller object:
                           PriceTotaller totaller = new PriceTotaller();
                           // Create a new delegate object associated with the nonstatic
                           // method AddBookToTotal on the object totaller:
                           bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);

                           System.Console.WriteLine("Average Paperback Book Price: ${0:#.##}",
                           totaller.AveragePrice());
                  }

                 // Initialize the book database with some test books:
                 static void AddBooks(BookDB bookDB)
                 {
                         bookDB.AddBook("The C Programming Language",
                                  "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
                         bookDB.AddBook("The Unicode Standard 2.0",
                                  "The Unicode Consortium", 39.95m, true);
                         bookDB.AddBook("The MS-DOS Encyclopedia",
                                  "Ray Duncan", 129.95m, false);
                         bookDB.AddBook("Dogbert's Clues for the Clueless",
                                  "Scott Adams", 12.00m, true);
                  }
         }
}


/* Output:
Paperback Book Titles:
The C Programming Language
The Unicode Standard 2.0
Dogbert's Clues for the Clueless
Average Paperback Book Price: $23.97
*/

 

Sử Dụng Delegate Để Truyền Giá Trị Giữa Các Form

Để có thể viết được một ứng dụng phần mềm, bạn phải biết cách truyền giá trị qua lại giữa các Form.

Tuy nhiên, khi ta muốn lấy giá trị từ nhiều Form khác, chắc chúng ta sẽ gặp rắc rối với những cách làm thông thường. Delegate sẽ giúp chúng ta giải quyết vấn đề.

Trước hết, tôi sẽ trình bày cho các bạn cách truyền giá trị theo cách thông thường. Khác...

Delegate và Event trong C#

1. Delegate là gì ?
Delegate là khái niệm trong C#, nó giống như con trỏ hàm của C++. Delegate là con trỏ trỏ vào các hàm có cùng đối(số lượng đối và kiểu đối giống nhau)
Tại sao phải dùng ?
- Delegate là cơ sở của Event do đó khi ta muốn sử dụng event ta phải sử dụng Delegate
Cách sử dụng

 

public delegate void LearningDelegate(string s);

class A
{
    public void MethodA()
    {
        Console.WriteLine("Method A");
    }
    public void MethodB()
    {
        Console.WriteLine("Method B");
    }
}

class Program
{
    public static void Main()
    {
        A a = new A();
        LearningDelegate deg;
        deg = new LearningDeleage(a.MethodA);
        deg();
        deg = new LearningDeleage(a.MethodB);
        deg();
    }
}

 

2. Event là gì ?
Event là các sự kiện xảy ra khi chạy chương trình (sự kiện click của button, sự kiện giá trị của comboBox thay đổi,…)
Tại sao phải dùng Event ?
Dùng Event giúp chúng ta xử lý code lịnh hoạt và đơn giản hơn. Khi sử dụng Event thì chúng ta không cần quan tâm đến việc khai nào thì đặt hàm xử lý vì khi event phát sinh nó sẽ tự động gọi hàm xử lý ra để thực hiện.
Ví dụ : Khi bạn Add/Remove 1 item vào mảng thì chương trình hiện ra thông báo “Add” hoặc “Remove”. Với cách xử lý truyền thống khi Add hoặc Remove sẽ có 1 hàm để xử lý đoạn lệnh thông báo, nhưng với Event thì mỗi khi sự kiện Add/Remove xảy ra thì tự động chương trình sẽ gọi hàm xử lý. Điều này làm giảm công sức của coder


Cách sử dung : tạo ra 3 lớp
- Lớp 1 : khai báo đối tượng có event và các event của đối tượng đó
- Lớp 2 : đăng ký event của với chương trình
- Lớp 3 : chạy chương trình, tạo đối tượng có event và thực thi

 

namespace Practice_Console
{
    public delegate void AddItemHandler(object sender, EventArgs e);
    public delegate void RemoveItemHandler(object sender, EventArgs e);

    class ListWithEventChanged
    {
        public event AddItemHandler AddItem;
        public event RemoveItemHandler RemoveItem;

        protected virtual void OnAddItem(EventArgs e)
        {
            if (AddItem != null)
                AddItem(this, e);
        }
        protected virtual void OnRemoveItem(EventArgs e)
        {
            if (RemoveItem != null)
                RemoveItem(this, e);
        }

        public void Add(string s)
        {
            Console.WriteLine(s);
            OnAddItem(EventArgs.Empty);
        }

        public void Remove(string s)
        {
            Console.WriteLine(s);
            OnRemoveItem(EventArgs.Empty);
        }
    }

    class EventListener
    {
        public EventListener(ListWithEventChanged list)
        {
            ListWithEventChanged List = new ListWithEventChanged();
            List = list;
            List.AddItem += new AddItemHandler(List_AddItem);
            List.RemoveItem += new RemoveItemHandler(List_RemoveItem);
        }

        private void List_AddItem(object sender, EventArgs e)
        {
            Console.WriteLine("Phat sinh su kien Add");
        }

        private void List_RemoveItem(object sender, EventArgs e)
        {
            Console.WriteLine("Phat sinh su kien Remove");
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            ListWithEventChanged list = new ListWithEventChanged();
            EventListener listener = new EventListener(list);
            list.Add("Add");
            Console.ReadLine();
            list.Remove("Remove");
            Console.ReadLine();
        }
    }
}

Nguồn: http://dotnet.fibo.us/2009/08/15/delegate-va-event-trong-c/