跳轉到內容

.NET 開發基金會/使用事件

來自華夏公益教科書,開放的書籍,開放的世界


系統型別和集合:使用事件和委託


使用事件和委託

[編輯 | 編輯原始碼]

考試目標:透過使用事件和委託來控制 .NET Framework 應用程式元件之間的互動。

(參考 System 名稱空間)

委託類 - MSDN

委託儲存指向一個或多個函式的指標,並在需要時呼叫它們。
委託的一種常見用法是用於事件處理。引發事件的類不知道哪些物件或方法想要接收該事件,因此需要在引發事件的物件和接收事件的物件之間建立一箇中介或指標機制。委託可以用作函式指標來完成此操作。
委託是一個類,但與普通類不同,它有一個簽名。在 .Net 框架中,您只需宣告委託,CLR 就會處理類的實現。
   //delegate declaration
   public delegate void AlarmEventHandler(object sender,EventArgs e);
第一個完整的示例只是宣告一個委託型別,然後宣告該型別的變數,將一個函式分配給它並執行委託變數,這將執行該函式。
C# 示例

簡單的委託

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab01
   {
       // declare the delegate type
       public delegate int IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Assign the delegate
               IntOperDel deleg = pgm.Increment;
               // Executing the delegate
               int res = deleg(32);
               Console.WriteLine("First value: " + res.ToString());
               // Second assign
               deleg = pgm.Decrement;
               // Second execution
               res = deleg(32);
               Console.WriteLine("First value: " + res.ToString());
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to the delegate
           public int Increment(int n)
           {
               return n + 1;
           }
           // Second function to be assigned to the delegate
           public int Decrement(int n)
           {
               return n - 1;
           }
       }
   }
第二個委託示例實現了回撥函式的概念。一個函式用委託作為引數呼叫。當它執行委託時,它不知道到底執行了什麼函式。它的部分行為被委託給了作為引數傳遞的函式(透過委託)。
C# 示例

回撥委託

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab02
   {
       // declare the delegate type
       public delegate int IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Assign the delegate
               IntOperDel deleg = pgm.Increment;
               // Calling a function that will execute de delegate
               // as part of its own logic
               pgm.ExecuteCallBack(deleg);
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // Function to be assigned to a delegate
           public int Increment(int n)
           {
               return n + 1;
           }
           // Function called with a delegate as parameter
           public void ExecuteCallBack(IntOperDel deleg)
           {
               int res = deleg(32);
               Console.WriteLine("Result from executing the callback: " + res.ToString());
           }
       }
   }
第三個委託示例使用委託成員來產生與事件相同的模式。請注意,在沒有至少分配一個函式的情況下執行委託成員將導致異常。此外,使用 += 運算子分配 2 個函式將在執行委託時執行 2 個函式。如果委託具有返回值,則將返回最後執行的函式的返回值。
C# 示例

委託成員

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab03
   {
       // declare the delegate type
       public delegate void IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(int n)
           {
               int res = n + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(int n)
           {
               int res = n - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member of the delegate type
           public IntOperDel delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               this.delMember(32);
           }
       }
   }
第四個示例是事件的基本示例。它與第三個示例完全相同,只是在成員宣告中添加了event關鍵字,並在呼叫事件之前進行了測試,因為“空”事件會引發異常。此示例清楚地表明事件只不過是一個多播委託。
C# 示例

事件成員

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab04
   {
       // declare the delegate type
       public delegate void IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(int n)
           {
               int res = n + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(int n)
           {
               int res = n - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event IntOperDel delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(32);
           }
       }
   }
執行與事件關聯的函式稱為引發事件。
與事件關聯的函式稱為事件處理程式

EventArgs 類 - MSDN

按照慣例,事件使用一個返回 void 並接受 2 個引數的委託
  • 一個 System.Object 型別的物件,其中包含對引發事件的物件的引用。
  • 來自從 EventArgs 派生的類的物件,其中包含從引發事件的物件傳遞給事件處理程式的資料。
EventArgs 類本身不包含任何資料。
因此,沒有資料的事件將使用以下形式的委託
public delegate void DelegateTypeName (object sender, EventArgs e)
這個簡單的事件示例與上一個示例相同,使用 IntEventArgs 類將 int 引數傳遞給事件處理程式,並且所有引數都已更改以遵循事件的呼叫約定。
C# 示例

具有遵循呼叫約定的委託的事件

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace EventLab01
   {
       // the class containing the event data passed to the event handler
       public class IntEventData : EventArgs
       {
           public int IntParm = 0;
           // constructor
           public IntEventData(int i)
           {
               IntParm = i;
           }
       }
       // the delegate type
       public delegate void IntOperDel(object sender, IntEventData e);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(object sender, IntEventData e)
           {
               int res = e.IntParm + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(object sender, IntEventData e)
           {
               int res = e.IntParm - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event IntOperDel delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(this, new IntEventData(32));
           }
       }
   }

EventHandler 委託 - MSDNMSDN

System 名稱空間中定義了兩個特殊的委託來幫助您進行事件宣告。
第一個是 EventHandler 委託。它不傳遞任何資料。不傳遞任何資料的事件可以宣告為
public event EventHandler EventName
無需宣告自定義委託。
這是宣告不傳遞任何資料的事件的通常方式。
C# 示例

使用 EventHandler 委託的事件

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace EventLab03
   {
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to the event
           public void Increment(object sender, EventArgs e)
           {
               int res = 32 + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to the event
           public void Decrement(object sender, EventArgs e)
           {
               int res = 32 - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event EventHandler delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(this, null);
           }
       }
   }
第二個是 EventHandler<T> 通用委託,其中 T 是從 EventArgs 派生的型別
public event EventHandler<T> EventName
同樣不需要宣告自定義委託型別。
這是宣告將資料傳遞給事件處理程式的事件的通常方式。
請注意,在這種情況下,您仍然需要宣告從 EventArgs 派生的型別 T。
C# 示例

利用 EventHandler<T> 的事件

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace EventLab02
   {
       // the class containing the event data passed to the event handler
       public class IntEventData : EventArgs
       {
           public int IntParm = 0;
           // constructor
           public IntEventData(int i)
           {
               IntParm = i;
           }
       }
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(object sender, IntEventData e)
           {
               int res = e.IntParm + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(object sender, IntEventData e)
           {
               int res = e.IntParm - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event EventHandler<IntEventData> delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(this, new IntEventData(32));
           }
       }
   }
這總結了事件和委託的基本示例。
華夏公益教科書