.NET 開發基金會/使用事件
外觀
| .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));
}
}
}
- 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));
}
}
}
- 這總結了事件和委託的基本示例。