14.1 發(fā)布者/訂閱者
- 發(fā)布者(publisher):發(fā)布某個事件的類或結(jié)構(gòu),其他類可以在該事件發(fā)生時得到通知。
- 訂閱者(subscriber):注冊并在事件發(fā)生時得到通知的類或結(jié)構(gòu)
- 事件處理程序(event handler) :由訂閱者注冊到事件的方法,在發(fā)布者觸發(fā)事件時執(zhí)行。事件處理程序方法可以定義在事件所在的類或結(jié)構(gòu)中,也可以定義在不同的類或結(jié)構(gòu)中。
- 觸發(fā)(raise)事件 調(diào)用(invoke)或觸發(fā)(fire)事件的術(shù)語:當事件觸發(fā)時,所有注冊到它的方法都會被依次調(diào)用。
有關(guān)事件的私有委托
- 事件提供了對它的私有控制委托的結(jié)構(gòu)化訪問。即你無法直接訪問委托。
- 事件中可用的操作比委托少,對于事件我們只可以添加、刪除或調(diào)用事件處理程序。
- 事件被觸發(fā)時,它調(diào)用委托來依次調(diào)用調(diào)用列表中的方法。

14.2 源代碼組件概覽
一個完整的組件由5部分組成:
- 委托類型聲明:事件和事件處理程序必須有共同的簽名和返回類型,他們通過委托類型進行描述。
- 事件處理程序聲明:訂閱者類中會在事件觸發(fā)時執(zhí)行的方法聲明??梢允秋@式命名的方法,也可以是匿名方法或Lambda表達式。
- 事件聲明:發(fā)布者類必須聲明一個訂閱者類可以注冊的事件成員。當聲明的事件為public時,稱為發(fā)布了事件。
- 事件注冊:訂閱者必須訂閱事件才能在它被觸發(fā)時得到通知。
-
觸發(fā)事件的代碼:發(fā)布者類中“觸發(fā)”事件并導(dǎo)致調(diào)用注冊的所有事件處理程序的代碼。
使用事件時的5個源代碼組件
static class Program
{
static void Main()
{
Incrementer incrementer = new Incrementer();
Dozens dozensCounter = new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
Console.ReadKey();
}
//發(fā)布者類
class Incrementer
{
public delegate void Handler();//委托類型聲明
public event Handler CountADozen;//事件聲明
public void DoCount()
{
for (int i = 1; i < 100; i++)
{
if (i % 12 == 0 && CountADozen != null)
{
CountADozen();//觸發(fā)事件代碼
}
}
}
}
//訂閱者類
class Dozens
{
public int DozensCount { get; private set; }
public Dozens(Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountADozen += IncrementerDozensCount;//事件注冊
}
void IncrementerDozensCount()//事件處理程序聲明
{
DozensCount++;
}
}
}
14.6 標準事件的用法
程序事件的異步處理是使用C#事件的絕佳場景。WindowsGUI編程廣泛地使用了事件,.NET框架提供了一個標準模式。事件使用的標準模式的根本是System命名空間聲明的EventHandler委托類型。
public delegate void EventHandler(object sender, EventArgs e);
- 第一個參數(shù)用來保存觸發(fā)事件的對象的引用。由于是object類型,可以匹配任何類型的實例。
- 第二個參數(shù)用來保存狀態(tài)信息,指明什么類型適用于該應(yīng)用程序;
- 返回類型是 void
- EventArgs設(shè)計為不能傳遞任何數(shù)據(jù)。它用于不需要傳遞數(shù)據(jù)的事件處理程序——通常會被忽略。
- 如果要傳遞數(shù)據(jù),必須聲明一個派生自EventArgs的類,使用合適的字段來保存需要傳遞的數(shù)據(jù)。
修改上述程序使之使用標準EventHandler委托:
static class Program
{
static void Main()
{
Incrementer incrementer = new Incrementer();
Dozens dozensCounter = new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
Console.ReadKey();
}
class Incrementer
{
public event EventHandler CountADozen;//使用系統(tǒng)定義的EventHandler委托
public void DoCount()
{
for (int i = 1; i < 100; i++)
{
if (i % 12 == 0 && CountADozen != null)
{
CountADozen(this, null);//觸發(fā)事件時使用EventHandler的參數(shù)
}
}
}
}
class Dozens
{
public int DozensCount { get; private set; }
public Dozens(Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountADozen += IncrementerDozensCount;
}
void IncrementerDozensCount(object sender, EventArgs e)//事件處理程序的簽名必須與委托的簽名匹配
{
DozensCount++;
}
}
}
14.6.1 通過擴展EventArgs來傳遞參數(shù)
要向事件處理程序的第二個參數(shù)傳入數(shù)據(jù),需要聲明一個派生自EventArgs的自定義類,可以保存要傳的數(shù)據(jù)。
static class Program
{
static void Main()
{
Incrementer incrementer = new Incrementer();
Dozens dozensCounter = new Dozens(incrementer);
incrementer.DoCount();
Console.WriteLine("Number of dozens = {0}", dozensCounter.DozensCount);
Console.ReadKey();
}
public class IncrementerEventArgs : EventArgs//自定義類派生自EventArgs
{
public int IterationCount { get; set; }//存儲一個整數(shù)
}
class Incrementer
{
public event EventHandler<IncrementerEventArgs> CountADozen;//使用、自定義類的泛型委托
public void DoCount()
{
IncrementerEventArgs args = new IncrementerEventArgs();//自定義類對象
for (int i = 1; i < 100; i++)
{
if (i % 12 == 0 && CountADozen != null)
{
CountADozen(this, args);//觸發(fā)事件時傳遞參數(shù)
}
}
}
}
class Dozens
{
public int DozensCount { get; private set; }
public Dozens(Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountADozen += IncrementerDozensCount;
}
void IncrementerDozensCount(object sender, IncrementerEventArgs e)//事件處理程序的簽名必須與委托的簽名匹配
{
Console.WriteLine("Incremented at iteration: {0} in {1}", e.IterationCount, sender.ToString());
DozensCount++;
}
}
}
