為什么要使用事件而不是委托變量? 在 C#中的委托和事件 中,我提出了兩個(gè)為什么在 " /> 色婷婷综合久久久久中文一区二,亚洲成人精品,91在线一区二区

中文字幕日韩一区二区_国产一区二区av_国产毛片av_久久久久国产一区_色婷婷电影_国产一区二区精品

C#中的委托和事件學(xué)習(xí)(續(xù))第1/3頁(yè)

引言
本文將討論委托和事件一些更為細(xì)節(jié)的問(wèn)題,包括一些大家常問(wèn)到的問(wèn)題,以及事件訪問(wèn)器、異常處理、超時(shí)處理和異步方法調(diào)用等內(nèi)容。

為什么要使用事件而不是委托變量?
在 C#中的委托和事件 中,我提出了兩個(gè)為什么在類(lèi)型中使用事件向外部提供方法注冊(cè),而不是直接使用委托變量的原因。主要是從封裝性和易用性上去考慮,但是還漏掉了一點(diǎn),事件應(yīng)該由事件發(fā)布者觸發(fā),而不應(yīng)該由客戶(hù)端(客戶(hù)程序)來(lái)觸發(fā)。這句話(huà)是什么意思呢?請(qǐng)看下面的范例:

NOTE:注意這里術(shù)語(yǔ)的變化,當(dāng)我們單獨(dú)談?wù)撌录覀冋f(shuō)發(fā)布者(publisher)、訂閱者(subscriber)、客戶(hù)端(client)。當(dāng)我們討論Observer模式,我們說(shuō)主題(subject)和觀察者(observer)。客戶(hù)端通常是包含Main()方法的Program類(lèi)。

class Program {
static void Main(string[] args) {
Publishser pub = new Publishser();
Subscriber sub = new Subscriber();

pub.NumberChanged += new NumberChangedEventHandler(sub.OnNumberChanged);
pub.DoSomething(); // 應(yīng)該通過(guò)DoSomething()來(lái)觸發(fā)事件
pub.NumberChanged(100); // 但可以被這樣直接調(diào)用,對(duì)委托變量的不恰當(dāng)使用
}
}

// 定義委托
public delegate void NumberChangedEventHandler(int count);

// 定義事件發(fā)布者
public class Publishser {
private int count;
public NumberChangedEventHandler NumberChanged; // 聲明委托變量
//public event NumberChangedEventHandler NumberChanged; // 聲明一個(gè)事件

public void DoSomething() {
// 在這里完成一些工作 ...

if (NumberChanged != null) { // 觸發(fā)事件
count++;
NumberChanged(count);
}
}
}

// 定義事件訂閱者
public class Subscriber {
public void OnNumberChanged(int count) {
Console.WriteLine("Subscriber notified: count = {0}", count);
}
}

上面代碼定義了一個(gè)NumberChangedEventHandler委托,然后我們創(chuàng)建了事件的發(fā)布者Publisher和訂閱者Subscriber。當(dāng)使用委托變量時(shí),客戶(hù)端可以直接通過(guò)委托變量觸發(fā)事件,也就是直接調(diào)用pub.NumberChanged(100),這將會(huì)影響到所有注冊(cè)了該委托的訂閱者。而事件的本意應(yīng)該為在事件發(fā)布者在其本身的某個(gè)行為中觸發(fā),比如說(shuō)在方法DoSomething()中滿(mǎn)足某個(gè)條件后觸發(fā)。通過(guò)添加event關(guān)鍵字來(lái)發(fā)布事件,事件發(fā)布者的封裝性會(huì)更好,事件僅僅是供其他類(lèi)型訂閱,而客戶(hù)端不能直接觸發(fā)事件(語(yǔ)句pub.NumberChanged(100)無(wú)法通過(guò)編譯),事件只能在事件發(fā)布者Publisher類(lèi)的內(nèi)部觸發(fā)(比如在方法pub.DoSomething()中),換言之,就是NumberChanged(100)語(yǔ)句只能在Publisher內(nèi)部被調(diào)用。

大家可以嘗試一下,將委托變量的聲明那行代碼注釋掉,然后取消下面事件聲明的注釋。此時(shí)程序是無(wú)法編譯的,當(dāng)你使用了event關(guān)鍵字之后,直接在客戶(hù)端觸發(fā)事件這種行為,也就是直接調(diào)用pub.NumberChanged(100),是被禁止的。事件只能通過(guò)調(diào)用DoSomething()來(lái)觸發(fā)。這樣才是事件的本意,事件發(fā)布者的封裝才會(huì)更好。

就好像如果我們要定義一個(gè)數(shù)字類(lèi)型,我們會(huì)使用int而不是使用object一樣,給予對(duì)象過(guò)多的能力并不見(jiàn)得是一件好事,應(yīng)該是越合適越好。盡管直接使用委托變量通常不會(huì)有什么問(wèn)題,但它給了客戶(hù)端不應(yīng)具有的能力,而使用事件,可以限制這一能力,更精確地對(duì)類(lèi)型進(jìn)行封裝。

NOTE:這里還有一個(gè)約定俗稱(chēng)的規(guī)定,就是訂閱事件的方法的命名,通常為“On事件名”,比如這里的OnNumberChanged。

為什么委托定義的返回值通常都為void?
盡管并非必需,但是我們發(fā)現(xiàn)很多的委托定義返回值都為void,為什么呢?這是因?yàn)槲凶兞靠梢怨┒鄠€(gè)訂閱者注冊(cè),如果定義了返回值,那么多個(gè)訂閱者的方法都會(huì)向發(fā)布者返回?cái)?shù)值,結(jié)果就是后面一個(gè)返回的方法值將前面的返回值覆蓋掉了,因此,實(shí)際上只能獲得最后一個(gè)方法調(diào)用的返回值。可以運(yùn)行下面的代碼測(cè)試一下。除此以外,發(fā)布者和訂閱者是松耦合的,發(fā)布者根本不關(guān)心誰(shuí)訂閱了它的事件、為什么要訂閱,更別說(shuō)訂閱者的返回值了,所以返回訂閱者的方法返回值大多數(shù)情況下根本沒(méi)有必要。

class Program {
static void Main(string[] args) {
Publishser pub = new Publishser();
Subscriber1 sub1 = new Subscriber1();
Subscriber2 sub2 = new Subscriber2();
Subscriber3 sub3 = new Subscriber3();

pub.NumberChanged += new GeneralEventHandler(sub1.OnNumberChanged);
pub.NumberChanged += new GeneralEventHandler(sub2.OnNumberChanged);
pub.NumberChanged += new GeneralEventHandler(sub3.OnNumberChanged);
pub.DoSomething(); // 觸發(fā)事件
}
}

// 定義委托
public delegate string GeneralEventHandler();

// 定義事件發(fā)布者
public class Publishser {
public event GeneralEventHandler NumberChanged; // 聲明一個(gè)事件
public void DoSomething() {
if (NumberChanged != null) { // 觸發(fā)事件
string rtn = NumberChanged();
Console.WriteLine(rtn); // 打印返回的字符串,輸出為Subscriber3
}
}
}

// 定義事件訂閱者
public class Subscriber1 {
public string OnNumberChanged() {
return "Subscriber1";
}
}
public class Subscriber2 { /* 略,與上類(lèi)似,返回Subscriber2*/ }
public class Subscriber3 { /* 略,與上類(lèi)似,返回Subscriber3*/ }

如果運(yùn)行這段代碼,得到的輸出是Subscriber3,可以看到,只得到了最后一個(gè)注冊(cè)方法的返回值。

AspNet技術(shù)C#中的委托和事件學(xué)習(xí)(續(xù))第1/3頁(yè),轉(zhuǎn)載需保留來(lái)源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 精品自拍视频在线观看 | 国产精品亚洲精品 | 久久久久久高清 | 黄视频国产 | 国产亚洲一区二区在线观看 | 一道本在线 | 91精品国产91久久久久久吃药 | 日韩福利在线 | 国产一级片免费看 | 男人视频网站 | 亚洲视频在线一区 | 国产一区二区三区精品久久久 | 淫片一级国产 | 久久久久国产精品 | 日韩一区二区三区在线播放 | 亚洲综合五月天婷婷 | 欧美极品在线观看 | 久久无毛 | 波多野结衣一区二区三区在线观看 | 久久综合狠狠综合久久 | 精品一区二区三区四区 | 一区二区三区精品在线 | 亚洲一区欧美 | 国产精品日日做人人爱 | 久久久久免费精品国产小说色大师 | 天天人人精品 | 一区二区影院 | 成人午夜网 | 国产一级特黄真人毛片 | 久久精品国产一区二区三区 | 高清色视频| 在线免费观看黄色 | 香蕉久久av | 午夜小影院 | 中文字幕日韩欧美一区二区三区 | 久久久久久亚洲欧洲 | 97人人超碰 | 国产精品一级 | 久久国产精品一区二区三区 | 黄色成人免费在线观看 | 国产一区二区a |