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

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