第一篇:腦電圖(EEG)與事件相關(guān)電位(ERP)的區(qū)別
腦電圖(EEG)與事件相關(guān)電位(ERP)有什么區(qū)別?
(一)腦電圖(EEG)檢查:是在頭部按一定部位放置8-16個(gè)電極,經(jīng)腦電圖機(jī)將腦細(xì)胞固有的生物電活動(dòng)放大并連續(xù)描記在紙上的圖形。正常情況下,腦電圖有一定的規(guī)律性,當(dāng)腦部尤其是皮層有病變時(shí),規(guī)律性受到破壞,波形即發(fā)生變化,對其波形進(jìn)行分析,可輔助臨床對及腦部疾病進(jìn)行診斷。
腦波按其頻率分為:δ波(1-3c/s)θ波(4-7c/s)、α波(8-13c/s)、β波(14-25c/s)γ波(25c/s以上),δ與θ波稱為慢波,β與γ波稱為快波。依年齡不同其基本波的頻率也不同,如3歲以下小兒以δ波為主,3-6歲以θ波為主,隨年齡增長,α波逐漸增多,到成年人時(shí)以α波為主,但年齡之間無明確的嚴(yán)格界限,如有的兒童4、5歲枕部α波已很明顯。正常成年人在清醒、安靜、閉眼時(shí),腦波的基本節(jié)律是枕部α波為主,其他部位則是以α波間有少量慢波為主。判斷腦波是否正常,主要是根據(jù)其年齡,對腦波的頻率、波幅、兩側(cè)的對稱性以及慢波的數(shù)量、部位、出現(xiàn)方式及有無病理波等進(jìn)行分析。許多腦部病變可引起腦波的異常。如顱內(nèi)占位性病變(尤其是皮層部位者)可有限局性慢波;散發(fā)性腦炎,絕大部分腦電圖呈現(xiàn)彌漫性高波幅慢波;此外如腦血管病、炎癥、外傷、代謝性腦病等都有各種不同程度的異常,但腦深部與線部位的病變陽性率很低。須加指出的是,腦電圖表現(xiàn)沒有特異性,必須結(jié)合臨床進(jìn)行綜合判斷,然而對于癲癇則有決定性的診斷價(jià)值,在闐癇發(fā)作間歇期,腦電圖可有陣發(fā)性高幅慢波、棘波、尖波、棘一慢波綜合等所謂“痛性放電”表現(xiàn)。為了提高腦電圖的陽性率,可依據(jù)不同的病變部位采用不同的電極放置方法。如鼻咽電極、鼓膜電極與蝶骨電極,在開顱時(shí)也可將電極置于皮層(皮層電極)或埋入腦深部結(jié)構(gòu)(深部電極);此外,還可使用各種誘發(fā)試驗(yàn),如睜閉眼、過度換氣、閃光刺激、睡眠誘發(fā)、剝奪睡眠誘發(fā)以及靜脈注射美解眠等。但蝶骨電極與美解眠誘發(fā)試驗(yàn)等方法,可給病人帶來痛苦與損害,須在有經(jīng)驗(yàn)者指導(dǎo)下進(jìn)行。隨著科技的日益發(fā)展,近年來又有了遙控腦電圖與24小時(shí)監(jiān)測腦電圖。
(二)腦電地形圖(BEAM)
是在EEG的基礎(chǔ)上,將腦電信號(hào)輸入電腦內(nèi)進(jìn)行再處理,通過模數(shù)轉(zhuǎn)換與付立葉轉(zhuǎn)換,將腦電信號(hào)轉(zhuǎn)換為數(shù)字信號(hào),處理成為腦電功率譜,按照不同頻帶進(jìn)行分類,依功率的多少分級(jí),最終使腦電信號(hào)轉(zhuǎn)換成一種能夠定量的二維腦波圖像,此種圖像能客觀地反映各部電位變化的空間分布狀態(tài),其定量標(biāo)志可以用數(shù)字或顏色表示,再用打印機(jī)打印在顱腦模式圖上,或貯存在軟盤上。它的優(yōu)越性在于能發(fā)現(xiàn)EEG中較難判別的細(xì)微異常,提高了陽性率,且病變部位圖像直觀醒目,定位比較準(zhǔn)確,從而客觀對大腦機(jī)能進(jìn)行評價(jià)。主要應(yīng)用于缺血性腦血管病的早期診斷及療效予后的評價(jià),小兒腦發(fā)育與腦波變化的研究,視覺功能的研究,大浮腫瘤的定位以及精神藥物的研究等。
(三)腦磁圖
電流在導(dǎo)體內(nèi)流動(dòng)進(jìn),導(dǎo)體周圍可以產(chǎn)生磁場。同理,腦細(xì)胞的電活動(dòng)也有極微弱的磁場,可用高靈敏度的磁場傳感器予以檢測,并記錄其隨時(shí)間變化的關(guān)系曲線,是即腦磁圖,其圖形與EEG圖形相似。與EEG相比,優(yōu)點(diǎn)是:可發(fā)現(xiàn)有臨床意義而又不能被EEG記錄到的波形,或檢測到皮質(zhì)局限性的異常電磁活動(dòng);此外,磁檢器不與頭皮接觸,也減少了干擾造成的偽差。若與EEG同時(shí)描記,還可對不同物理方位的皮質(zhì)群進(jìn)行分析。但由于屏蔽、電磁裝置以及其他設(shè)備復(fù)雜、昂貴,目前國內(nèi)尚無此項(xiàng)設(shè)備。
(四)誘發(fā)電位
給人體感官、感覺神經(jīng)或運(yùn)動(dòng)皮質(zhì)、運(yùn)動(dòng)神經(jīng)以刺激,興奮沿相應(yīng)的神經(jīng)通路向中樞或外周傳導(dǎo),在傳導(dǎo)過程中,產(chǎn)生的不斷組合傳遞的電位變化,即為誘發(fā)電位,對其加以分析,即或反映出不同部位的神經(jīng)功能狀態(tài)。由于誘發(fā)電位非常微小,須借助電腦對重復(fù)刺激的信號(hào)進(jìn)行疊加處理,將其放大,并從淹沒于肌電、腦電的背景中提取出來,才能加以描記。主要是對波形、主波的潛伏期、波峰間期與波幅等進(jìn)行分析,為臨床診斷提供參考,目前臨床常用的有視覺、腦干聽覺、體感、運(yùn)動(dòng)與事件相關(guān)誘發(fā)電位,以及視網(wǎng)膜圖與耳蝸電圖等,可分別反映視網(wǎng)膜、視覺通路、內(nèi)耳、聽神經(jīng)、腦干、外周神經(jīng)、脊髓后索、感覺皮質(zhì)以及上下運(yùn)動(dòng)神經(jīng)元的各種病變,事件相關(guān)誘發(fā)電位則用以判斷患者的注意力與反應(yīng)能力。誘發(fā)電位具有高度敏感性,對感覺障礙可進(jìn)行客觀評詁,對病變能進(jìn)行定量判斷。對心理精神領(lǐng)域可進(jìn)行一定的檢測,故當(dāng)前廣泛應(yīng)用于對神經(jīng)系統(tǒng)病變的早期診斷,病情隨訪,療效判斷,予后估計(jì),神經(jīng)系統(tǒng)發(fā)育情況的評估以及協(xié)助判斷昏迷性質(zhì)與腦死亡等。但圖形無特異性,必須結(jié)合臨床資料進(jìn)行判斷;不在有關(guān)神經(jīng)傳導(dǎo)徑路中的病變,不能發(fā)現(xiàn)異常。近年,誘發(fā)電位的頻譜分析與誘發(fā)電位地形圖也在臨床上逐漸開始應(yīng)用,進(jìn)一步提高了其臨床應(yīng)用價(jià)值。
(五)肌電圖(EMG)
是用肌電圖儀記錄神經(jīng)與肌肉的生物電活動(dòng),對其波形進(jìn)行測量分析,可以了解神經(jīng)、肌肉的功能狀態(tài),協(xié)助對下運(yùn)動(dòng)神經(jīng)元或肌肉疾病的診斷。目前常用的方法有三種:①針極肌電圖:亦稱普通肌電圖,是將特制的針電極刺入肌腹,或用表面電極置于肌肉表面皮膚,在示波器上或記錄紙上觀察肌肉在靜止、輕收縮、重收縮三種狀態(tài)下的電位變化,以幫助判斷疾病究系神經(jīng)源性或肌源性損害。②神經(jīng)傳導(dǎo)速度測定:也即運(yùn)動(dòng)神經(jīng)傳導(dǎo)速度(MCV)與感覺神經(jīng)傳導(dǎo)速度(SCV)測定。系在神經(jīng)干的近端(MCV)或遠(yuǎn)端(SCV)給以脈沖刺激,在遠(yuǎn)端效應(yīng)肌(MCV)或近端神經(jīng)走行部位(SCV)接收波形,測理兩點(diǎn)之間的潛伏期與距離,即可計(jì)算出運(yùn)動(dòng)神經(jīng)或感覺神經(jīng)傳導(dǎo)速度,主要用于了解神經(jīng)傳導(dǎo)功能情況。③其他:如重復(fù)頻率試驗(yàn),F(xiàn)波、H反射、牽張反射等檢查以及單纖維肌電圖檢查等,可進(jìn)一步了解神經(jīng)、肌肉、神經(jīng)一肌接頭以及脊髓反射弧的功能狀態(tài)。
(六)腦阻抗血流圖(REG)
是檢查頭部血管功能與供血情況的一種方法。其原理是通過放置在頭部的電極給以微弱的高頻電流,由于血液的電阻率最小,其電阻可隨心動(dòng)周期供血的變化而變化,這種節(jié)律性的阻抗變化,經(jīng)血流圖儀放大,可描記出波動(dòng)性曲線,對其進(jìn)行測量、計(jì)算、分析,可間接了解外周阻力、血管彈性與供血情況。本法簡便易行,但因影響因素比較多,如情緒、氣溫、檢查當(dāng)時(shí)的血管功能狀態(tài)等,故對其判斷應(yīng)加慎重。須結(jié)合臨床癥狀,體征等進(jìn)行判斷。常用于腦動(dòng)脈硬化、閉塞性腦血管病、偏頭痛以及藥物療效觀察等。
第二大項(xiàng).ERP
(一)事件相關(guān)電位的基本概念
對大腦高級(jí)心理活動(dòng)如認(rèn)知過程作出客觀評價(jià),我們很難將意識(shí)或思維單純歸于大腦某一部位組織、細(xì)胞或神經(jīng)遞質(zhì)的改變,因?yàn)閮H采用具體、微觀的自然科學(xué)手段如神經(jīng)分子生物學(xué)、神經(jīng)生化學(xué)難以解決具體的心理活動(dòng)。二十世紀(jì)六十年代,Sutton提出了事件相關(guān)電位的概念,通過平均疊加技術(shù)從頭顱表面記錄大腦誘發(fā)電位來反映認(rèn)知過程中大腦的神經(jīng)電生理改變,因?yàn)槭录嚓P(guān)電位與認(rèn)知過程有密切關(guān)系,故被認(rèn)為是“窺視”心理活動(dòng)的“窗口”。神經(jīng)電生理技術(shù)的發(fā)展,為研究大腦認(rèn)知活動(dòng)過程提供了新的方法與途徑。
事件相關(guān)電位(ERP)是一種特殊的腦誘發(fā)電位,通過有意地賦予刺激儀特殊的心理意義,利用多個(gè)或多樣的刺激所引起的腦的電位。它反映了認(rèn)知過程中大腦的神經(jīng)點(diǎn)生理的變化,也被稱為認(rèn)知電位,也就是指當(dāng)人們對某課題進(jìn)行認(rèn)知加工時(shí),從頭顱表面記錄到的腦點(diǎn)位。經(jīng)典的ERP主要成分包括P1、N1、P2、N2、P3,其中前三種稱為外源性稱為,而后兩種稱為內(nèi)源性成分。這幾種成分的主要特點(diǎn)是:首先不僅僅是大腦單純生理活動(dòng)的體現(xiàn),而且反映了心理活動(dòng)的某些方面;其次,它們的引出必須要有特殊的刺激安排,而且是兩個(gè)以上的刺激或者是刺激的變化。其中P3是ERP中最受關(guān)注與研究的一種內(nèi)源性成分,也是用于測謊的最主要指標(biāo)。因此,在某種程度上,P3就成了ERP的代名詞。
(二)誘發(fā)電位的特征
事件相關(guān)電位(ERP)是一種特殊的腦誘發(fā)電位,誘發(fā)電位(Evoked Potentials,EPs),也稱誘發(fā)反應(yīng)(Evoked Response),是指給予神經(jīng)系統(tǒng)(從感受器到大腦皮層)特定的刺激,或使大腦對刺激(正性或負(fù)性)的信息進(jìn)行加工,在該系統(tǒng)與腦的相應(yīng)部位產(chǎn)生的可以檢出的、與刺激有相對固定時(shí)間間隔(鎖時(shí)關(guān)系)與特定位相的生物電反應(yīng)。誘發(fā)電位應(yīng)具備如下特征:
1.必須在特定的部位才能檢測出來;
2.都有其特定的波形與電位分布;
3.誘發(fā)電位的潛伏期與刺激之間有較嚴(yán)格的鎖時(shí)關(guān)系,在給予刺激時(shí)幾乎立即或在一定時(shí)間內(nèi)瞬時(shí)出現(xiàn)。
(三)誘發(fā)電位的分類
誘發(fā)電位的分類方法有多種,依據(jù)刺激通道分為聽覺誘發(fā)電位、視覺誘發(fā)電位、體感誘發(fā)電位等;根據(jù)潛伏期長短分為早潛伏期誘發(fā)電位、中潛伏期誘發(fā)電位、晚(長)潛伏期誘發(fā)電位與慢波。臨床上實(shí)用起見,將誘發(fā)電位分為兩大類:與感覺或運(yùn)動(dòng)功能有關(guān)的外源性刺激相關(guān)電位與與認(rèn)知功能有關(guān)的內(nèi)源性事件相關(guān)電位(Event-Related PotentialS,ERPs)。
內(nèi)源性事件相關(guān)電位與外源性刺激相關(guān)電位有著明顯的不同。ERPs是在注意的基礎(chǔ)上,與識(shí)別、比較、判斷、記憶、決斷等心理活動(dòng)有關(guān),反映了認(rèn)知過程的不同方面,是了解大腦認(rèn)知功能活動(dòng)的“窗口”。經(jīng)典的ERPs成分包括P1、Nl、P2、N2、P3(P300),其中P1、N1、P2為ERPs的外源性(生理性)成分,受刺激物理特性影響;N2、P3為ERPs的內(nèi)源性(心理性)成分,不受刺激物理特性的影響,與被試的精神狀態(tài)與注意力有關(guān)?,F(xiàn)在ERPs的概念范圍有擴(kuò)大趨勢,廣義上講,ERPs尚包括N4(N400)、失匹配陰性波(Mismatch NegatiVity,MMN)、伴隨負(fù)反應(yīng)(Contigent NegatiVe Variaeion,CNV)等。但長期以來有人通常以P3作為事件相關(guān)電位的代稱,雖有失偏頗,但臨床應(yīng)用甚廣。
(四)事件相關(guān)電位的測試方法 事件相關(guān)電位屬于長潛伏期誘發(fā)電位,測試時(shí)一般要求被試者清醒,并在一定程度上參與其中。引出ERPs的刺激是按研究目的不同編制而成的不同刺激序列,包括兩種及兩種以上的刺激,其中一個(gè)刺激與標(biāo)準(zhǔn)刺激產(chǎn)生偏離,以啟動(dòng)被試的認(rèn)知活動(dòng)過程。如果由陽性的物理刺激啟動(dòng),除了由認(rèn)知活動(dòng)產(chǎn)生的內(nèi)源性成分,尚包括外源性刺激相關(guān)電位;如由陰性刺激來啟動(dòng)心理活動(dòng)過程,則引出由認(rèn)知加工而產(chǎn)生的內(nèi)源性成分。
P3為ERPs中重要的內(nèi)源性成分,現(xiàn)時(shí)對它的研究最為廣泛。多為神經(jīng)精神學(xué)科研究,如精神分裂癥、腦血管疾病與癡呆癥、智力低下等,通過研究P3的潛伏期、波幅、波形變化,反映認(rèn)知障礙或智能障礙及其程度,同時(shí)尚應(yīng)用于測謊研究。另有人將P3、CNV用作觀察神經(jīng)精神藥物治療效果的指標(biāo)。事件相關(guān)電位的另一內(nèi)源性成分N2為刺激以后200毫秒左右出現(xiàn)的負(fù)向波,反映大腦對刺激的初步加工,該波并非單一成分,而是一復(fù)合波,由N2a與N2b兩部分組成,N2a不受注意的影響,反映對刺激物理特性的初步加工。
刺激模式:刺激模式的設(shè)置是研究ERPs的關(guān)鍵,要求根據(jù)研究目的不同設(shè)計(jì)不同的刺激模式,包括兩種及以上不同概率的刺激序列,并以特定或隨機(jī)方式出現(xiàn)。包括視覺刺激模式、聽覺刺激模式、軀體感覺刺激模式。聽覺刺激模式包括三類:1.隨機(jī)作業(yè)(OB刺激序列);2.雙隨機(jī)作業(yè);3.選擇注意。OB刺激序列(oddball paradigm):通過耳機(jī)同步給高調(diào)、低調(diào)純音,低概率音作為靶刺激,誘發(fā)ERPs。通常靶刺激概率為10—30%,非靶概率70一90%,刺激間隔多采用1.5—2秒,刺激持續(xù)時(shí)間通常為40—80毫秒,反應(yīng)方式為或默數(shù)靶信號(hào)出現(xiàn)次數(shù)或按鍵反應(yīng)。
(五)影響事件相關(guān)電位的因素 ▲物理因素
刺激的概率:靶刺激概率越小,P3的波幅越高,反之,波幅減小。一般靶刺激與非靶刺激的比例為20:80;刺激的時(shí)間間隔:間隔越長,P3波幅越高;刺激的感覺通道:聽、視、體感感覺通道皆可引出ERPs,但其潛伏期及波幅不盡相同。
▲心理因素
事件相關(guān)電位檢測過程中一般要求被試者主動(dòng)參與,因而被試者的覺醒狀態(tài)、注意力是否集中皆可影響結(jié)果。另外,由于被試者只有識(shí)別靶刺激并作出反應(yīng)才能誘發(fā)出ERPs成分,因此,作業(yè)難度對測試結(jié)果也有影響,難度加大時(shí),波幅降低,潛伏期延長。
▲生理因素
年齡:不同年齡P3的波幅及潛伏期不同。潛伏期與年齡呈正相關(guān),隨年齡增加而延長,而波幅與年齡呈負(fù)相關(guān)。在兒童及青少年,波幅較高;分布:ERPs各成分有不同的頭皮分布。
事件相關(guān)電位(ERP)作為可以反映大腦高級(jí)思維活動(dòng)的一種客觀方法在研究認(rèn)知功能中得到廣泛的應(yīng)用, 而作為其內(nèi)源形成分的P300是ERP中最典型、最常用的成分與認(rèn)知過程密切相關(guān), 被視為“窺視”心理活動(dòng)的一個(gè)窗口,并認(rèn)為它是腦研究的一種新型手段。
事件相關(guān)電位具有高時(shí)間分辨率的特點(diǎn),使其在揭示認(rèn)知的時(shí)間過程方面極具優(yōu)勢,能鎖時(shí)性的反映認(rèn)知的動(dòng)態(tài)過程.該方法已經(jīng)成為研究腦認(rèn)知活動(dòng)的重要手段.P300是較早發(fā)現(xiàn)的內(nèi)源性事件相關(guān)電位成分,主要與人在從事某一任務(wù)時(shí)的認(rèn)知活動(dòng)如:注意、辨別、及工作記憶有關(guān)。P300可能代表期待的感覺信息得到確認(rèn)與知覺任務(wù)的結(jié)束,目前已被廣泛用來研究認(rèn)知功能。其潛伏期反映對刺激物評價(jià)或歸類所需要的時(shí)間即反應(yīng)速度,隨作業(yè)難度的增加而延長,而波幅反映了心理負(fù)荷的量,即被試投入到任務(wù)重的腦力資源的多少。雖然P300對認(rèn)知損害評價(jià)的臨床應(yīng)用較廣,但近年來的研究證實(shí)P300的腦內(nèi)源不止一個(gè),而是與多種認(rèn)知加工有關(guān),所以其在認(rèn)知損害特征的精確描述方面有一定的局限性。
第三項(xiàng)
腦成像
腦成像就是通過最新技術(shù)使得神經(jīng)科學(xué)家可以“看到活體腦的內(nèi)部”。這些腦成像方法可以在以下方面為神經(jīng)科學(xué)家提供幫助:理解腦特定區(qū)域與其功能之間的關(guān)系。對受神經(jīng)疾病影響的腦區(qū)進(jìn)行定位。發(fā)明新方法治療腦部疾病。
腦成像包括:
(一)計(jì)算機(jī)X線斷層攝影(CT掃描)CT掃描時(shí),一束X射線穿過頭部,感光膠片形成圖像。這種方法可以產(chǎn)生腦部剖面成像。這種方法只顯示腦結(jié)構(gòu),而非腦功能。
(二)正電子發(fā)射斷層掃描術(shù)(PET)掃描儀通過檢測被注射入或被吸入的放射物可以產(chǎn)生腦圖像。經(jīng)常使用的放射性物質(zhì)包括氧,氟利昂,碳與氮。這些物質(zhì)進(jìn)入血液后被輸送到使用這些物質(zhì)的腦區(qū)。于是,氧與葡萄糖就會(huì)積聚在新陳代謝較活躍的腦區(qū)。放射性物質(zhì)衰變時(shí)會(huì)發(fā)射出一個(gè)中子與一個(gè)正電子。當(dāng)正電子撞擊電子時(shí),兩者都被破壞,放射出兩道伽瑪射線。伽瑪射線檢測器記錄下發(fā)出伽瑪射線的腦區(qū)。這種方法提供了腦的功能視圖。優(yōu)點(diǎn):
1、提供了腦活動(dòng)的圖像。缺點(diǎn):
1、價(jià)格昂貴;
2、使用放射性物質(zhì)
(三)磁共振成像(MRI)磁共振成像使用無線電頻率信號(hào)檢測,信號(hào)產(chǎn)生于磁場中轉(zhuǎn)移的無線電波。它提供了腦的解剖視圖。優(yōu)點(diǎn):
1、沒有 X-射線或放射物質(zhì);
2、提供詳細(xì)的不同維度的腦圖像;
3、安全無痛,非侵入性;
4、病人無需做特殊準(zhǔn)備(除了去除所有金屬物品),病人之前可以進(jìn)食。缺點(diǎn):
1、價(jià)格昂貴。
2、不適用于帶有金屬物品的病人,如起搏器。
3、不適用于不配合的病人,因?yàn)椴∪吮仨毎察o地平躺。
4、不適用于患有幽閉恐怖癥的病人(害怕狹小地方),但現(xiàn)在已出現(xiàn)設(shè)計(jì)更加寬敞的新型磁共振系統(tǒng)。
(四)功能磁共振成像(fMRI)
功能磁共振成像對流向特定腦區(qū)的血液的變化進(jìn)行檢測。它同時(shí)提供腦的解剖與功能視圖。
(五)血管造影術(shù) 在染料被注入血液中后,血管造影術(shù)使用一束X射線。這種方法可以提供腦血管圖像。
還有就是 SPECT 單光子發(fā)射計(jì)算機(jī)斷層成像術(shù)(Single-Photon Emission Computed Tomography,SPECT)與正電子發(fā)射斷層成像術(shù)(Positron Emission Tomography,PET)是核醫(yī)學(xué)的兩種CT技術(shù),由于它們都是對從病人體內(nèi)發(fā)射的γ射線成像,故統(tǒng)稱發(fā)射型計(jì)算機(jī)斷層成像術(shù)(Emission Computed Tomography,ECT)。
SPECT的基本本成像原理是:γ照相機(jī)探頭的每個(gè)靈敏點(diǎn)探測沿一條投影線(Ray)進(jìn)來的γ光子,其測量值代表人體在該投影線上的放射性之與。在同一條直線上的靈敏點(diǎn)可探測人體一個(gè)斷層上的放射性藥物,它們的輸出稱作該斷層的一維投影(Projection)。圖中各條投影線都垂直于探測器并互相平行,故稱之為平行束,探測器的法線與X軸的交角θ稱為觀測角(View)。γ照相機(jī)是二維探測器,安裝了平行孔準(zhǔn)直器后,可以同時(shí)獲取多個(gè)斷層的平行束投影,這就是平片。平片表現(xiàn)不出投影線上各點(diǎn)的前后關(guān)系。要想知道人體在縱深方向上的結(jié)構(gòu),就需要從不同角度進(jìn)行觀測。可以證明,知道了某個(gè)斷層在所有觀測角的一維投影,就能計(jì)算出該斷層的圖像。從投影求解斷層圖像的過程稱作重建(Reconstruction)。這種斷層成像術(shù)離不開計(jì)算機(jī),所以稱作計(jì)算機(jī)斷層成像術(shù)(Computered Tomography,CT)。CT設(shè)備的主要功能是獲取投影數(shù)據(jù)與重建斷層圖像。
ECT顯像的主要臨床應(yīng)用
1、骨骼顯像。
骨骼顯像是早期診斷惡性腫瘤骨轉(zhuǎn)移的首選方法??蛇M(jìn)行疾病分期、骨痛評價(jià)、預(yù)后判斷、療效觀察與探測病理骨折的危險(xiǎn)部位。
2、心臟灌注斷層顯像
心肌缺血的診斷??稍u價(jià)冠狀動(dòng)脈病變范圍,對冠心病危險(xiǎn)性進(jìn)行分級(jí);評價(jià)冠脈狹窄引起的心肌血流灌注量改變及側(cè)枝循環(huán)的功能,評價(jià)心肌細(xì)胞活力;對心肌梗塞的預(yù)后評價(jià)與療效觀察;觀察心臟搭橋術(shù)及介入性治療后心肌缺血改善情況。
心肌梗死的診斷,心梗伴缺血的診斷,判斷心肌細(xì)胞存活情況。
心肌病、室壁瘤的鑒別診斷。
3、甲狀腺顯像
異位甲狀腺的診斷與定位。具有獨(dú)特價(jià)值。
甲狀腺結(jié)節(jié)功能的判斷與良惡性鑒別,具有較高診斷價(jià)值。
高分化甲狀腺癌轉(zhuǎn)移灶的定位與診斷。
甲狀腺大小與重量的估計(jì)。
4、局部腦血流斷層顯像
缺血性腦血管意外的診斷。具有較高診斷價(jià)值。
癲癇致癇灶的定位診斷。癲癇發(fā)作間期的陽性率高達(dá)60%(而XCT與MRI的陽性率約25%)。
判斷腦腫瘤的血運(yùn),鑒別術(shù)后或放療后復(fù)發(fā)與瘢痕。
癡呆分型。尤其對早老性癡呆(Alzheimer?。┑脑\斷有較高價(jià)值。
5、腎動(dòng)態(tài)顯像及腎圖檢查。
了解腎動(dòng)脈病變及雙腎血供情況;對腎功能及分腎功能的判斷;了解上尿路通暢情況及對尿路梗阻的診斷;監(jiān)測移植腎血流灌注與功能情況;以及了解糖尿病對腎功能的影響。其它顯像的主要臨床應(yīng)用
甲狀旁腺顯像:對甲狀旁腺腺瘤的診斷與定位。
腎上腺髓質(zhì)顯像:對嗜鉻細(xì)胞瘤及其轉(zhuǎn)移灶的診斷及定位,及惡性嗜鉻細(xì)胞瘤131I-MIBG治療后隨訪。
肺灌注顯像與肺通氣顯像:對肺動(dòng)脈血栓栓塞癥的診斷與療效判斷。
肝臟膠體顯像、肝血流與肝血池顯像:對肝海綿狀血管瘤的診斷。
肝膽動(dòng)態(tài)顯像:用于鑒別梗阻性黃疸與肝細(xì)胞性黃疸;鑒別先天性膽道閉鎖與嬰肝綜合征及療效觀察。
腸道出血顯像:最適用于探測胃以下、乙狀結(jié)腸以上的活動(dòng)性下消化道出血。
異位胃粘膜顯像:對美克爾憩室的診斷及定位,對腸梗阻或腸套疊(懷疑與美克爾憩室或小腸重復(fù)畸形有關(guān))的鑒別診斷。
[編輯本段]事件相關(guān)電位
ERP反映了認(rèn)知過程中大腦的神經(jīng)點(diǎn)生理的變化,也被稱為認(rèn)知電位,也就是指當(dāng)人們對某課題進(jìn)行認(rèn)知加工時(shí),從頭顱表面記錄到的腦點(diǎn)位[3]。
提問者: zhtao_deutsch-一級(jí)最佳答案病人的疑慮帶有很大的普遍性,很多病人總是擔(dān)心醫(yī)生給病人做檢查是不是必要的,是不是在重復(fù)收費(fèi)檢查等等。
1、MRI(磁共振成像血管造影)診斷技術(shù),完全脫離了利用X線吸收成像的原理,對于病人沒有放射性傷害,MRI的成像原理是體內(nèi)H質(zhì)子的信號(hào),經(jīng)過計(jì)算機(jī)處理后得到的圖像。
頭顱磁共振成像(MRI)檢查較CT更為敏感,具有多方向切層、多參數(shù)成像的特點(diǎn),能更精確地顯示病變部位、范圍大小及組織學(xué)特性,是發(fā)現(xiàn)腦內(nèi)部結(jié)構(gòu)病變的首選方法,但價(jià)格較為昂貴。
2、腦電圖檢查的作用及意義
人體的大腦有140億個(gè)腦細(xì)胞,其中有2.5億個(gè)神經(jīng)細(xì)胞。神經(jīng)細(xì)胞活動(dòng)時(shí)可以產(chǎn)生各種生物電信號(hào),腦電圖就是利用腦電圖機(jī)記錄人體大腦生物電的信息的。只要將腦電圖機(jī)的探測儀電極貼在頭皮上,儀器就能收到腦電活動(dòng)整個(gè)過程中電位的變化,這時(shí)掃描筆便在移動(dòng)著的圖紙上描繪出各種曲線。由于曲線的頻率與振幅不同,就構(gòu)成了不同的波形,形成了腦電圖波。
一般來說,每個(gè)人的腦電圖都有其固有的特征。腦電圖波分為慢活動(dòng)波與快活動(dòng)波,在正常生理?xiàng)l件下,有著正常的生理節(jié)律與固有特征,而當(dāng)腦電圖出現(xiàn)異常時(shí),則提示有病變的可能。因此,在對大腦生理功能進(jìn)行評判時(shí),可以進(jìn)行腦電圖檢查。由于腦電圖是一種無創(chuàng)傷性的檢查方法,所以可以多次進(jìn)行重復(fù)檢查。
3、腦血流圖又叫腦電阻圖,它是利用電阻變化的原理,描記隨心臟跳動(dòng)而變化的腦血流波動(dòng)圖形。腦血流圖比較能夠客觀地反映腦血管的緊張度與血管的彈性變化,對判斷腦血管病有一定的參考價(jià)值。
以上的檢查項(xiàng)目各有各的用途,一般不能相互替代。
第二篇:ERP與SCM的區(qū)別
理論模型和方法
多年來,人們一直在堅(jiān)持不懈地將數(shù)學(xué)規(guī)劃等方法用于企業(yè)安排計(jì)劃和管理上,漸漸形成了MRP法和數(shù)學(xué)規(guī)劃法這兩種主要的計(jì)劃編制方法,后者由于受到如建模困難、運(yùn)算量大等客觀條件的限制,發(fā)展比較遲緩,而MRP法則由于省略了一些實(shí)際存在、但又難以求解的因素,變得簡單易算,獲得了較好的成效和發(fā)展。但是,人們逐漸發(fā)現(xiàn)那些因素往往是不容忽視的,加之計(jì)算機(jī)計(jì)算速度的飛速發(fā)展,使得采用數(shù)學(xué)規(guī)劃方法不再困難,人們開始以常駐計(jì)算機(jī)內(nèi)存的方式采用數(shù)學(xué)規(guī)劃方法編制計(jì)劃,這種全新的計(jì)劃方法就是SCM的開端。
SCM采用了多種數(shù)學(xué)解析的優(yōu)化模型和規(guī)則,是基于約束理論進(jìn)行計(jì)劃的,它考慮了物料、設(shè)備、人員、場所、時(shí)間和技術(shù)等所有的約束因素,對不同的目標(biāo)可以通過不同的規(guī)制進(jìn)行優(yōu)化。而ERP的理論模型過于簡單和陳舊,它的計(jì)劃模型和提前期的計(jì)算方法等都無法模擬今日復(fù)雜多變的業(yè)務(wù)過程。例如,ERP作計(jì)劃的前提假設(shè)是企業(yè)具有無限的物料和能力,計(jì)劃模型是無約束的;又如,ERP一般采用簡單的線性公式T= A+BX計(jì)算產(chǎn)品的提前期,但每種物品每一次的采購提前期都可能存在較大差別,無法用這種簡單公式來準(zhǔn)確計(jì)算。
管理范圍
ERP只能對其內(nèi)部資源進(jìn)行管理。然而,單靠企業(yè)內(nèi)部的業(yè)務(wù)改進(jìn)所獲得的收效已變得越來越有限,企業(yè)逐漸將管理焦點(diǎn)轉(zhuǎn)移到超越企業(yè)之外的供應(yīng)鏈管理和上下游的業(yè)務(wù)協(xié)同上。SCM則能夠滿足供應(yīng)鏈橫向一體化運(yùn)作的要求,在考慮了資源約束、優(yōu)化和決策的技術(shù)支持下,有效利用和整合外部資源。
SCM另一個(gè)優(yōu)于ERP之處是它能夠模擬和改善財(cái)務(wù)指標(biāo),特別是收入、成本和資產(chǎn)利用率指標(biāo)。它不僅僅是簡單地降低成本,而是利用不同的方式來滿足市場和客戶的需求。
編制計(jì)劃
SCM擴(kuò)大了計(jì)劃范圍,通過不同的規(guī)則對不同業(yè)務(wù)進(jìn)行計(jì)劃,并可對單一目標(biāo)和多目標(biāo)進(jìn)行優(yōu)化的計(jì)劃;而且,SCM的計(jì)劃是并發(fā)的、計(jì)劃時(shí)段是連續(xù)的,綜合、完整地考慮了約束問題,生成的提前期是彈性的,可以對供應(yīng)鏈和企業(yè)的各項(xiàng)業(yè)務(wù)進(jìn)行計(jì)劃,一次性地考慮業(yè)務(wù)流程的縱向和橫向的協(xié)調(diào),無需一個(gè)個(gè)地依次制訂計(jì)劃。而ERP編制計(jì)劃是按順序進(jìn)行的,計(jì)劃時(shí)段是離散的,生成的提前期是固定的,僅面向某一功能的計(jì)劃,計(jì)劃的能見度只限于局部,幾乎不考慮約束。
同時(shí),SCM的計(jì)劃覆蓋了所有的業(yè)務(wù),計(jì)劃模型可以做得足夠的詳細(xì),覆蓋了長、中、短周期,可以實(shí)現(xiàn)倒排、順排和中間排,其精細(xì)程度可從年、月、周一直到天、小時(shí)和分鐘。SCM還能夠隨時(shí)根據(jù)生產(chǎn)和客戶需求的變化進(jìn)行重排計(jì)劃,量化地反映甚至超前于市場的需求,例如變化的資源和約束,用戶的優(yōu)先權(quán)等。它可以實(shí)現(xiàn)一個(gè)可持續(xù)轉(zhuǎn)變的流程,使得重排計(jì)劃能夠?qū)γ恳淮我馔庾兓M(jìn)行隨時(shí)處理。而ERP有時(shí)按天做計(jì)劃都很困難,更無法精確到小時(shí)和分鐘,也很難做到快速地重排計(jì)劃。最后,在生成計(jì)劃后,SCM可以根據(jù)“評價(jià)計(jì)劃成本”標(biāo)準(zhǔn)評價(jià)計(jì)劃成本,并與企業(yè)的財(cái)務(wù)指標(biāo)進(jìn)行對比和衡量,進(jìn)一步核實(shí)其可行性,但ERP無法對做出的計(jì)劃成本進(jìn)行評價(jià)。業(yè)務(wù)管理
SCM在業(yè)務(wù)管理上具有比ERP更好、更多的功能。
首先,SCM具有極強(qiáng)的實(shí)時(shí)承諾性,它的承諾標(biāo)準(zhǔn)能為客戶提供準(zhǔn)確的交貨日期。雖然ERP的可用量檢查ATP也具有某種承諾能力,但僅是建立在對現(xiàn)有庫存檢查的基礎(chǔ)上,而 SCM在ATP的基礎(chǔ)上,還通過對需求承諾能力和對訂單承諾能力的檢查、擴(kuò)展的生產(chǎn)可用性檢查和對獲利能力的檢查等功能,以對客戶做出準(zhǔn)確的交貨承諾,并在商談?dòng)唵蔚牡谝粫r(shí)間就能確定該訂單是否能夠獲利;
第二,SCM能對供應(yīng)鏈上的資源進(jìn)行優(yōu)化調(diào)配,將供應(yīng)鏈上的某種稀缺資源預(yù)先分派給具有較高優(yōu)先級(jí)別的客戶或渠道的需求;
第三,SCM的計(jì)劃范圍擴(kuò)展到了企業(yè)之外,能生成跨企業(yè)的協(xié)同計(jì)劃,實(shí)時(shí)了解伙伴們的業(yè)務(wù)變化情況,及時(shí)進(jìn)行重排計(jì)劃,保持高度的靈活性和預(yù)見性,以快速響應(yīng)市場需求,ERP則無法滿足這種需求;
第四,SCM可以動(dòng)態(tài)計(jì)算提前期,它的提前期標(biāo)準(zhǔn)提供了一個(gè)優(yōu)于ERP的特性,ERP邏輯使用固定的提前期進(jìn)行計(jì)劃,這對整個(gè)供應(yīng)鏈運(yùn)行具有若干負(fù)面的影響;
第五,SCM可以對供應(yīng)鏈的需求、供給和約束進(jìn)行監(jiān)控,實(shí)時(shí)地將這三者進(jìn)行比較,一旦出現(xiàn)不匹配時(shí)立刻發(fā)出預(yù)警信號(hào),并執(zhí)行智能的邏輯操作使它們重新恢復(fù)平衡,重新達(dá)到同步,這也是ERP無法實(shí)現(xiàn)的。
總的來說,ERP只能告訴你應(yīng)該做什么,而SCM則能幫助你決定怎樣去做。例如,供應(yīng)商和客戶的位置變化將怎樣影響運(yùn)輸成本?增加或取消一個(gè)配送中心,或越庫作業(yè)將如何影響運(yùn)輸成本?這些都是ERP無法解答,而必須讓位給SCM來解決的問題。
事務(wù)處理雖然SCM具有眾多的計(jì)劃、優(yōu)化和決策功能,但它卻不具備某些事務(wù)處理和數(shù)據(jù)維護(hù)功能,例如,貨物的接收、盤點(diǎn)與出庫,工單/采購單發(fā)放、發(fā)票 /文檔管理、會(huì)計(jì)管理,對項(xiàng)目主文件/BOM、列表進(jìn)行維護(hù)等。而ERP則可以完成這些功能。目前,有些SCM系統(tǒng)也擴(kuò)展了它的功能,增加了供應(yīng)鏈執(zhí)行系統(tǒng)SCE,由該系統(tǒng)來完成上述工作。
第三篇:MES與ERP的區(qū)別
天智MES與用友ERP的區(qū)別與補(bǔ)充
ERP 是MES的上一級(jí)管理系統(tǒng)。MES 是叫做制造執(zhí)行系統(tǒng),屬于企業(yè)管理中的關(guān)乎生產(chǎn)制造細(xì)節(jié)的管理層,但是又不具體參與生產(chǎn)制造的環(huán)節(jié)。MES是位于上層計(jì)劃管理系統(tǒng)與底層工業(yè)控制之間,面向車間層的管理系統(tǒng)。
主要區(qū)別:
1、雖然同屬軟件系統(tǒng)、平臺(tái)管理同屬用于輔助企業(yè)管理,但MES是ERP的延升。
2、MES是軟硬件集成系統(tǒng),而ERP是純軟件系統(tǒng),缺少硬件設(shè)備的支持。
3、MES管理的是車間現(xiàn)場與實(shí)物的管理系統(tǒng),而ERP是管理信息數(shù)據(jù)系統(tǒng)。
4、MES依靠條形碼設(shè)備自動(dòng)采集完工數(shù)量等信息,而ERP全靠人工輸入,工作量大,易出錯(cuò)。
MES是通過信息傳遞,對從訂單下達(dá)到產(chǎn)品完成整個(gè)的生產(chǎn)過程進(jìn)行優(yōu)化管理。當(dāng)工廠里有實(shí)時(shí)事件發(fā)生時(shí),MES能對此及時(shí)做出反應(yīng)、報(bào)告,并用當(dāng)前的準(zhǔn)確數(shù)據(jù)對它們進(jìn)行指導(dǎo)和處理。從而使其既能提高工廠及時(shí)交貨能力、改善物料的流通性能又提高生產(chǎn)回報(bào)率。
目前國際上所有流程企業(yè),以及國內(nèi)石化、鋼鐵等行業(yè)均廣泛應(yīng)用MES+ERP模式來規(guī)劃和發(fā)展企業(yè)信息系統(tǒng)。
ERP無法實(shí)現(xiàn)的功能需MES作為補(bǔ)充:
1、出現(xiàn)用戶產(chǎn)品投訴的時(shí)候,能否根據(jù)產(chǎn)品文字號(hào)碼追溯這批產(chǎn)品的所有生產(chǎn)過程信息?能否立即查明它的:原料供應(yīng)商、操作機(jī)臺(tái)、操作人員、經(jīng)過的工序、生產(chǎn)時(shí)間日期和關(guān)鍵的工藝參數(shù)?
2、同一條生產(chǎn)線需要混合組裝多種型號(hào)產(chǎn)品的時(shí)候,能否自動(dòng)校驗(yàn)和操作提示以防止工人部件裝配錯(cuò)誤、產(chǎn)品生產(chǎn)流程錯(cuò)誤、產(chǎn)品混裝和貨品交接錯(cuò)誤?
3、過去12小時(shí)之內(nèi)生產(chǎn)線上出現(xiàn)最多的5種產(chǎn)品缺陷是什么?次品數(shù)量各是多少?
4、目前倉庫以及前工序、中工序、后工序線上的每種產(chǎn)品數(shù)量各是多少?要分別供應(yīng)給哪些供應(yīng)商?何時(shí)能夠及時(shí)交貨?
5、生產(chǎn)線和加工設(shè)備有多少時(shí)間在生產(chǎn),多少時(shí)間在停轉(zhuǎn)和空轉(zhuǎn)?影響設(shè)備生產(chǎn)潛能的最主要原因是:設(shè)備故障?調(diào)度失誤?材料供應(yīng)不及時(shí)?工人培訓(xùn)不夠?還是工藝指標(biāo)不合理?
6、能否對產(chǎn)品的質(zhì)量檢測數(shù)據(jù)自動(dòng)進(jìn)行統(tǒng)計(jì)和分析,精確區(qū)分產(chǎn)品質(zhì)量的隨機(jī)波動(dòng)與異常波動(dòng),將質(zhì)量隱患消滅于萌芽之中?
7、能否廢除人工報(bào)表,自動(dòng)統(tǒng)計(jì)每個(gè)過程的生產(chǎn)數(shù)量、合格率和缺陷代碼?
第四篇:ERP與MRP2的區(qū)別
ERP同MRPⅡ的主要區(qū)別
·在資源管理范圍方面的差別
MRPII主要側(cè)重對企業(yè)內(nèi)部人、財(cái)、物等資源的管理,ERP系統(tǒng)在MRPII的基礎(chǔ)上擴(kuò)展了管理范圍,它把客戶需求和企業(yè)內(nèi)部的制造活動(dòng)、以及供應(yīng)商的制造資源整合在一起,形成企業(yè)一個(gè)完整的供應(yīng)鏈并對供應(yīng)鏈上所有環(huán)節(jié)如訂單、采購、庫存、計(jì)劃、生產(chǎn)制造、質(zhì)量控制、運(yùn)輸、分銷、服務(wù)與維護(hù)、財(cái)務(wù)管理、人事管理、實(shí)驗(yàn)室管理、項(xiàng)目管理、配方管理等進(jìn)行有效管理。
·在生產(chǎn)方式管理方面的差別
MRPII系統(tǒng)把企業(yè)歸類為幾種典型的生產(chǎn)方式進(jìn)行管理,如重復(fù)制造、批量生產(chǎn)、按訂單生產(chǎn)、按訂單裝配、按庫存生產(chǎn)等,對每一種類型都有一套管理標(biāo)準(zhǔn)。而在80年代末、90年代初期,為了緊跟市場的變化,多品種、小批量生產(chǎn)以及看板式生產(chǎn)等則是企業(yè)主要采用的生產(chǎn)方式,由單一的生產(chǎn)方式向混合型生產(chǎn)發(fā)展,ERP則能很好地支持和管理混合型制造環(huán)境,滿足了企業(yè)的這種多角化經(jīng)營需求。
·在管理功能方面的差別
ERP除了MRPII系統(tǒng)的制造、分銷、財(cái)務(wù)管理功能外,還增加了支持整個(gè)供應(yīng)鏈上物料流通體系中供、產(chǎn)、需各個(gè)環(huán)節(jié)之間的運(yùn)輸管理和倉庫管理;支持生產(chǎn)保障體系的質(zhì)量管理、實(shí)驗(yàn)室管理、設(shè)備維修和備品備件管理;支持對工作流(業(yè)務(wù)處理流程)的管理?!ぴ谑聞?wù)處理控制方面的差別
MRPII是通過計(jì)劃的及時(shí)滾動(dòng)來控制整個(gè)生產(chǎn)過程,它的實(shí)時(shí)性較差,一般只能實(shí)現(xiàn)事中控制。而ERP系統(tǒng)支持在線分析處理OLAP(OnlineAnalyticalProcessing)、售后服務(wù)即質(zhì)量反饋,強(qiáng)調(diào)企業(yè)的事前控制能力,它可以將設(shè)計(jì)、制造、銷售、運(yùn)輸?shù)韧ㄟ^集成來并行地進(jìn)行各種相關(guān)的作業(yè),為企業(yè)提供了對質(zhì)量、適應(yīng)變化、客戶滿意、績效等關(guān)鍵問題的實(shí)時(shí)分析能力。此外,在MRPII中,財(cái)務(wù)系統(tǒng)只是一個(gè)信息的歸結(jié)者,它的功能是將供、產(chǎn)、銷中的數(shù)量信息轉(zhuǎn)變?yōu)閮r(jià)值信息,是物流的價(jià)值反映。而ERP系統(tǒng)則將財(cái)務(wù)計(jì)劃和價(jià)值控制功能集成到了整個(gè)供應(yīng)鏈上。
·在跨國(或地區(qū))經(jīng)營事務(wù)處理方面的差別
現(xiàn)在企業(yè)的發(fā)展,使得企業(yè)內(nèi)部各個(gè)組織單元之間、企業(yè)與外部的業(yè)務(wù)單元之間的協(xié)調(diào)變得越來越多和越來越重要,ERP系統(tǒng)應(yīng)用完整的組織架構(gòu),從而可以支持跨國經(jīng)營的多國家地區(qū)、多工廠、多語種、多幣制應(yīng)用需求。
·在計(jì)算機(jī)信息處理技術(shù)方面的差別
隨著IT技術(shù)的飛速發(fā)展,網(wǎng)絡(luò)通信技術(shù)的應(yīng)用,使得ERP系統(tǒng)得以實(shí)現(xiàn)對整個(gè)供應(yīng)鏈信息進(jìn)行集成管理。ERP系統(tǒng)采用客戶/服務(wù)器(C/S)體系結(jié)構(gòu)和分布式數(shù)據(jù)處理技術(shù),支持Internet/Intranet/Extranet、電子商務(wù)(E-business、E-commerce)、電子數(shù)據(jù)交換(EDI)。此外,還能實(shí)現(xiàn)在不同
第五篇:委托與事件的區(qū)別
委托與事件的區(qū)別
委托 和 事件在.Net Framework中的應(yīng)用非常廣泛,然而,較好地理解委托和事件對很多接觸C#時(shí)間不長的人來說并不容易。它們就像是一道檻兒,過了這個(gè)檻的人,覺得真是太容易了,而沒有過去的人每次見到委托和事件就覺得心里別(biè)得慌,混身不自在。本文中,我將通過兩個(gè)范例由淺入深地講述什么是委托、為什么要使用委托、事件的由來、.Net Framework中的委托和事件、委托和事件對Observer設(shè)計(jì)模式的意義,對它們的中間代碼也做了討論。
將方法作為方法的參數(shù)
我們先不管這個(gè)標(biāo)題如何的繞口,也不管委托究竟是個(gè)什么東西,來看下面這兩個(gè)最簡單的方法,它們不過是在屏幕上輸出一句問候的話語: public void GreetPeople(string name){ // 做某些額外的事情,比如初始化之類,此處略 EnglishGreeting(name);} public void EnglishGreeting(string name){ Console.WriteLine(“Morning, ” + name);}
暫且不管這兩個(gè)方法有沒有什么實(shí)際意義。GreetPeople用于向某人問好,當(dāng)我們傳遞代表某人姓名的name參數(shù),比如說“Jimmy”,進(jìn)去的時(shí)候,在這個(gè)方法中,將調(diào)用EnglishGreeting方法,再次傳遞name參數(shù),EnglishGreeting則用于向屏幕輸出 “Morning, Jimmy”。
現(xiàn)在假設(shè)這個(gè)程序需要進(jìn)行全球化,哎呀,不好了,我是中國人,我不明白“Morning”是什么意思,怎么辦呢?好吧,我們再加個(gè)中文版的問候方法:
public void ChineseGreeting(string name){ Console.WriteLine(“早上好, ” + name);}
這時(shí)候,GreetPeople也需要改一改了,不然如何判斷到底用哪個(gè)版本的Greeting問候方法合適呢?在進(jìn)行這個(gè)之前,我們最好再定義一個(gè)枚舉作為判斷的依據(jù):
public enum Language{ English, Chinese } public void GreetPeople(string name, Language lang){ //做某些額外的事情,比如初始化之類,此處略 swith(lang){ case Language.English: EnglishGreeting(name);break;case Language.Chinese: ChineseGreeting(name);break;} }
OK,盡管這樣解決了問題,但我不說大家也很容易想到,這個(gè)解決方案的可擴(kuò)展性很差,如果日后我們需要再添加韓文版、日文版,就不得不反復(fù)修改枚舉和GreetPeople()方法,以適應(yīng)新的需求。
在考慮新的解決方案之前,我們先看看 GreetPeople的方法簽名:
public void GreetPeople(string name, Language lang)
我們僅看 string name,在這里,string 是參數(shù)類型,name 是參數(shù)變量,當(dāng)我們賦給name字符串“jimmy”時(shí),它就代表“jimmy”這個(gè)值;當(dāng)我們賦給它“張子陽”時(shí),它又代表著“張子陽”這個(gè)值。然后,我們可以在方法體內(nèi)對這個(gè)name進(jìn)行其他操作。哎,這簡直是廢話么,剛學(xué)程序就知道了。
如果你再仔細(xì)想想,假如GreetPeople()方法可以接受一個(gè)參數(shù)變量,這個(gè)變量可以代表另一個(gè)方法,當(dāng)我們給這個(gè)變量賦值 EnglishGreeting的時(shí)候,它代表著 EnglsihGreeting()這個(gè)方法;當(dāng)我們給它賦值ChineseGreeting 的時(shí)候,它又代表著ChineseGreeting()方法。我們將這個(gè)參數(shù)變量命名為 MakeGreeting,那么不是可以如同給name賦值時(shí)一樣,在調(diào)用 GreetPeople()方法的時(shí)候,給這個(gè)MakeGreeting 參數(shù)也賦上值么(ChineseGreeting或者EnglsihGreeting等)?然后,我們在方法體內(nèi),也可以像使用別的參數(shù)一樣使用MakeGreeting。但是,由于MakeGreeting代表著一個(gè)方法,它的使用方式應(yīng)該和它被賦的方法(比如ChineseGreeting)是一樣的,比如: MakeGreeting(name);
好了,有了思路了,我們現(xiàn)在就來改改GreetPeople()方法,那么它應(yīng)該是這個(gè)樣子了:
public void GreetPeople(string name, *** MakeGreeting){ MakeGreeting(name);}
注意到 ***,這個(gè)位置通常放置的應(yīng)該是參數(shù)的類型,但到目前為止,我們僅僅是想到應(yīng)該有個(gè)可以代表方法的參數(shù),并按這個(gè)思路去改寫GreetPeople方法,現(xiàn)在就出現(xiàn)了一個(gè)大問題:這個(gè)代表著方法的MakeGreeting參數(shù)應(yīng)該是什么類型的?
NOTE:這里已不再需要枚舉了,因?yàn)樵诮oMakeGreeting賦值的時(shí)候動(dòng)態(tài)地決定使用哪個(gè)方法,是ChineseGreeting還是 EnglishGreeting,而在這個(gè)兩個(gè)方法內(nèi)部,已經(jīng)對使用“morning”還是“早上好”作了區(qū)分。
聰明的你應(yīng)該已經(jīng)想到了,現(xiàn)在是委托該出場的時(shí)候了,但講述委托之前,我們再看看MakeGreeting參數(shù)所能代表的 ChineseGreeting()和EnglishGreeting()方法的簽名:
public void EnglishGreeting(string name)public void ChineseGreeting(string name)
如同name可以接受String類型的“true”和“1”,但不能接受bool類型的true和int類型的1一樣。MakeGreeting的 參數(shù)類型定義 應(yīng)該能夠確定 MakeGreeting可以代表的 方法種類,再進(jìn)一步講,就是MakeGreeting可以代表的方法 的 參數(shù)類型和返回類型。
于是,委托出現(xiàn)了:它定義了MakeGreeting參數(shù)所能代表的方法的種類,也就是MakeGreeting參數(shù)的類型。
NOTE:如果上面這句話比較繞口,我把它翻譯成這樣:string 定義了name參數(shù)所能代表的值的種類,也就是name參數(shù)的類型。
本例中委托的定義:
public delegate void GreetingDelegate(string name);
可以與上面EnglishGreeting()方法的簽名對比一下,除了加入了delegate關(guān)鍵字以外,其余的是不是完全一樣?
現(xiàn)在,讓我們再次改動(dòng)GreetPeople()方法,如下所示:
public void GreetPeople(string name, GreetingDelegate MakeGreeting){ MakeGreeting(name);}
如你所見,委托GreetingDelegate出現(xiàn)的位置與 string相同,string是一個(gè)類型,那么GreetingDelegate應(yīng)該也是一個(gè)類型,或者叫類(Class)。但是委托的聲明方式和類卻完全不同,這是怎么一回事?實(shí)際上,委托在編譯的時(shí)候確實(shí)會(huì)編譯成類。因?yàn)镈elegate是一個(gè)類,所以在任何可以聲明類的地方都可以聲明委托。更多的內(nèi)容將在下面講述,現(xiàn)在,請看看這個(gè)范例的完整代碼: using System;using System.Collections.Generic;using System.Text;
namespace Delegate { //定義委托,它定義了可以代表的方法的類型 public delegate void GreetingDelegate(string name);
class Program {
private static void EnglishGreeting(string name){ Console.WriteLine(“Morning, ” + name);}
private static void ChineseGreeting(string name){ Console.WriteLine(“早上好, ” + name);}
//注意此方法,它接受一個(gè)GreetingDelegate類型的方法作為參數(shù)
private static void GreetPeople(string name, GreetingDelegate MakeGreeting){ MakeGreeting(name);}
static void Main(string[] args){ GreetPeople(“Jimmy Zhang”, EnglishGreeting);GreetPeople(“張子陽”, ChineseGreeting);Console.ReadKey();} } }
輸出如下:
Morning, Jimmy Zhang 早上好, 張子陽
我們現(xiàn)在對委托做一個(gè)總結(jié):
委托是一個(gè)類,它定義了方法的類型,使得可以將方法當(dāng)作另一個(gè)方法的參數(shù)來進(jìn)行傳遞,這種將方法動(dòng)態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語句,同時(shí)使得程序具有更好的可擴(kuò)展性。將方法綁定到委托
看到這里,是不是有那么點(diǎn)如夢初醒的感覺?于是,你是不是在想:在上面的例子中,我不一定要直接在GreetPeople()方法中給 name參數(shù)賦值,我可以像這樣使用變量:
static void Main(string[] args){ string name1, name2;name1 = “Jimmy Zhang”;name2 = “張子陽”;
GreetPeople(name1, EnglishGreeting);GreetPeople(name2, ChineseGreeting);Console.ReadKey();}
而既然委托GreetingDelegate 和 類型 string 的地位一樣,都是定義了一種參數(shù)類型,那么,我是不是也可以這么使用委托?
static void Main(string[] args){ GreetingDelegate delegate1, delegate2;delegate1 = EnglishGreeting;delegate2 = ChineseGreeting;
GreetPeople(“Jimmy Zhang”, delegate1);GreetPeople(“張子陽”, delegate2);Console.ReadKey();}
如你所料,這樣是沒有問題的,程序一如預(yù)料的那樣輸出。這里,我想說的是委托不同于string的一個(gè)特性:可以將多個(gè)方法賦給同一個(gè)委托,或者叫將多個(gè)方法綁定到同一個(gè)委托,當(dāng)調(diào)用這個(gè)委托的時(shí)候,將依次調(diào)用其所綁定的方法。在這個(gè)例子中,語法如下:
static void Main(string[] args){ GreetingDelegate delegate1;delegate1 = EnglishGreeting;// 先給委托類型的變量賦值
delegate1 += ChineseGreeting;// 給此委托變量再綁定一個(gè)方法
// 將先后調(diào)用 EnglishGreeting 與 ChineseGreeting 方法 GreetPeople(“Jimmy Zhang”, delegate1);Console.ReadKey();}
輸出為:
Morning, Jimmy Zhang 早上好, Jimmy Zhang
實(shí)際上,我們可以也可以繞過GreetPeople方法,通過委托來直接調(diào)用EnglishGreeting和ChineseGreeting:
static void Main(string[] args){ GreetingDelegate delegate1;delegate1 = EnglishGreeting;// 先給委托類型的變量賦值
delegate1 += ChineseGreeting;// 給此委托變量再綁定一個(gè)方法
// 將先后調(diào)用 EnglishGreeting 與 ChineseGreeting 方法 delegate1(“Jimmy Zhang”);Console.ReadKey();}
NOTE:這在本例中是沒有問題的,但回頭看下上面GreetPeople()的定義,在它之中可以做一些對于EnglshihGreeting和ChineseGreeting來說都需要進(jìn)行的工作,為了簡便我做了省略。
注意這里,第一次用的“=”,是賦值的語法;第二次,用的是“+=”,是綁定的語法。如果第一次就使用“+=”,將出現(xiàn)“使用了未賦值的局部變量”的編譯錯(cuò)誤。
我們也可以使用下面的代碼來這樣簡化這一過程:
GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);delegate1 += ChineseGreeting;// 給此委托變量再綁定一個(gè)方法
看到這里,應(yīng)該注意到,這段代碼第一條語句與實(shí)例化一個(gè)類是何其的相似,你不禁想到:上面第一次綁定委托時(shí)不可以使用“+=”的編譯錯(cuò)誤,或許可以用這樣的方法來避免:
GreetingDelegate delegate1 = new GreetingDelegate();delegate1 += EnglishGreeting;// 這次用的是 “+=”,綁定語法。delegate1 += ChineseGreeting;// 給此委托變量再綁定一個(gè)方法
但實(shí)際上,這樣會(huì)出現(xiàn)編譯錯(cuò)誤: “GreetingDelegate”方法沒有采用“0”個(gè)參數(shù)的重載。盡管這樣的結(jié)果讓我們覺得有點(diǎn)沮喪,但是編譯的提示:“沒有0個(gè)參數(shù)的重載”再次讓我們聯(lián)想到了類的構(gòu)造函數(shù)。我知道你一定按捺不住想探個(gè)究竟,但再此之前,我們需要先把基礎(chǔ)知識(shí)和應(yīng)用介紹完。
既然給委托可以綁定一個(gè)方法,那么也應(yīng)該有辦法取消對方法的綁定,很容易想到,這個(gè)語法是“-=”:
static void Main(string[] args){ GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);delegate1 += ChineseGreeting;// 給此委托變量再綁定一個(gè)方法
// 將先后調(diào)用 EnglishGreeting 與 ChineseGreeting 方法 GreetPeople(“Jimmy Zhang”, delegate1);Console.WriteLine();
delegate1-= EnglishGreeting;//取消對EnglishGreeting方法的綁定 // 將僅調(diào)用 ChineseGreeting GreetPeople(“張子陽”, delegate1);Console.ReadKey();} 輸出為:
Morning, Jimmy Zhang 早上好, Jimmy Zhang
早上好, 張子陽
讓我們再次對委托作個(gè)總結(jié):
使用委托可以將多個(gè)方法綁定到同一個(gè)委托變量,當(dāng)調(diào)用此變量時(shí)(這里用“調(diào)用”這個(gè)詞,是因?yàn)榇俗兞看硪粋€(gè)方法),可以依次調(diào)用所有綁定的方法。
事件的由來
我們繼續(xù)思考上面的程序:上面的三個(gè)方法都定義在Programe類中,這樣做是為了理解的方便,實(shí)際應(yīng)用中,通常都是 GreetPeople 在一個(gè)類中,ChineseGreeting和 EnglishGreeting 在另外的類中?,F(xiàn)在你已經(jīng)對委托有了初步了解,是時(shí)候?qū)ι厦娴睦幼鰝€(gè)改進(jìn)了。假設(shè)我們將GreetingPeople()放在一個(gè)叫GreetingManager的類中,那么新程序應(yīng)該是這個(gè)樣子的:
namespace Delegate { //定義委托,它定義了可以代表的方法的類型 public delegate void GreetingDelegate(string name);
//新建的GreetingManager類 public class GreetingManager{ public void GreetPeople(string name, GreetingDelegate MakeGreeting){ MakeGreeting(name);} }
class Program { private static void EnglishGreeting(string name){ Console.WriteLine(“Morning, ” + name);}
private static void ChineseGreeting(string name){ Console.WriteLine(“早上好, ” + name);}
static void Main(string[] args){ //......} } }
這個(gè)時(shí)候,如果要實(shí)現(xiàn)前面演示的輸出效果,Main方法我想應(yīng)該是這樣的:
static void Main(string[] args){ GreetingManager gm = new GreetingManager();gm.GreetPeople(“Jimmy Zhang”, EnglishGreeting);gm.GreetPeople(“張子陽”, ChineseGreeting);}
我們運(yùn)行這段代碼,嗯,沒有任何問題。程序一如預(yù)料地那樣輸出了: Morning, Jimmy Zhang 早上好, 張子陽
現(xiàn)在,假設(shè)我們需要使用上一節(jié)學(xué)到的知識(shí),將多個(gè)方法綁定到同一個(gè)委托變量,該如何做呢?讓我們再次改寫代碼:
static void Main(string[] args){ GreetingManager gm = new GreetingManager();GreetingDelegate delegate1;delegate1 = EnglishGreeting;delegate1 += ChineseGreeting;gm.GreetPeople(“Jimmy Zhang”, delegate1);} 輸出:
Morning, Jimmy Zhang 早上好, Jimmy Zhang
到了這里,我們不禁想到:面向?qū)ο笤O(shè)計(jì),講究的是對象的封裝,既然可以聲明委托類型的變量(在上例中是delegate1),我們何不將這個(gè)變量封裝到 GreetManager類中?在這個(gè)類的客戶端中使用不是更方便么?于是,我們改寫GreetManager類,像這樣:
public class GreetingManager{ //在GreetingManager類的內(nèi)部聲明delegate1變量 public GreetingDelegate delegate1;
public void GreetPeople(string name, GreetingDelegate MakeGreeting){ MakeGreeting(name);} }
現(xiàn)在,我們可以這樣使用這個(gè)委托變量:
static void Main(string[] args){ GreetingManager gm = new GreetingManager();gm.delegate1 = EnglishGreeting;gm.delegate1 += ChineseGreeting;
gm.GreetPeople(“Jimmy Zhang”, gm.delegate1);}
盡管這樣達(dá)到了我們要的效果,但是似乎并不美氣,光是第一個(gè)方法注冊用“=”,第二個(gè)用“+=”就讓人覺得別扭。此時(shí),輪到Event出場了,C# 中可以使用事件來專門完成這項(xiàng)工作,我們改寫GreetingManager類,它變成了這個(gè)樣子:
public class GreetingManager{ //這一次我們在這里聲明一個(gè)事件
public event GreetingDelegate MakeGreet;
public void GreetPeople(string name, GreetingDelegate MakeGreeting){ MakeGreeting(name);} }
很容易注意到:MakeGreet 事件的聲明與之前委托變量delegate1的聲明唯一的區(qū)別是多了一個(gè)event關(guān)鍵字??吹竭@里,你差不多明白到:事件其實(shí)沒什么不好理解的,聲明一個(gè)事件不過類似于聲明一個(gè)委托類型的變量而已。
我們想當(dāng)然地改寫Main方法: static void Main(string[] args){ GreetingManager gm = new GreetingManager();gm.MakeGreet = EnglishGreeting;// 編譯錯(cuò)誤1 gm.MakeGreet += ChineseGreeting;
gm.GreetPeople(“Jimmy Zhang”, gm.MakeGreet);//編譯錯(cuò)誤2 }
這次,你會(huì)得到編譯錯(cuò)誤:事件“Delegate.GreetingManager.MakeGreet”只能出現(xiàn)在 += 或-= 的左邊(從類型“Delegate.GreetingManager”中使用時(shí)除外)。
事件和委托的編譯代碼
這時(shí)候,我們不得不注釋掉編譯錯(cuò)誤的行,然后重新進(jìn)行編譯,再借助Reflactor來對 event的聲明語句做一探究,看看為什么會(huì)發(fā)生這樣的錯(cuò)誤:
public event GreetingDelegate MakeGreet;
可以看到,實(shí)際上盡管我們在GreetingManager里將 MakeGreet 聲明為public,但是,實(shí)際上MakeGreet會(huì)被編譯成 私有字段,難怪會(huì)發(fā)生上面的編譯錯(cuò)誤了,因?yàn)樗揪筒辉试S在GreetingManager類的外面以賦值的方式訪問。
我們進(jìn)一步看下MakeGreet所產(chǎn)生的代碼:
private GreetingDelegate MakeGreet;//對事件的聲明 實(shí)際是 聲明一個(gè)私有的委托變量
[MethodImpl(MethodImplOptions.Synchronized)] public void add_MakeGreet(GreetingDelegate value){ this.MakeGreet =(GreetingDelegate)Delegate.Combine(this.MakeGreet, value);}
[MethodImpl(MethodImplOptions.Synchronized)] public void remove_MakeGreet(GreetingDelegate value){ this.MakeGreet =(GreetingDelegate)Delegate.Remove(this.MakeGreet, value);}
現(xiàn)在已經(jīng)很明確了:MakeGreet 事件確實(shí)是一個(gè)GreetingDelegate類型的委托,只不過不管是不是聲明為public,它總是被聲明為private。另外,它還有兩個(gè)方法,分別是add_MakeGreet和remove_MakeGreet,這兩個(gè)方法分別用于注冊委托類型的方法和取消注冊,實(shí)際上也就是: “+= ”對應(yīng) add_MakeGreet,“-=”對應(yīng)remove_MakeGreet。而這兩個(gè)方法的訪問限制取決于聲明事件時(shí)的訪問限制符。
在add_MakeGreet()方法內(nèi)部,實(shí)際上調(diào)用了System.Delegate的Combine()靜態(tài)方法,這個(gè)方法用于將當(dāng)前的變量添加到委托鏈表中。我們前面提到過兩次,說委托實(shí)際上是一個(gè)類,在我們定義委托的時(shí)候:
public delegate void GreetingDelegate(string name);
當(dāng)編譯器遇到這段代碼的時(shí)候,會(huì)生成下面這樣一個(gè)完整的類: public class GreetingDelegate:System.MulticastDelegate{
public GreetingDelegate(object @object, IntPtr method);public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);public virtual void EndInvoke(IAsyncResult result);public virtual void Invoke(string name);}
關(guān)于這個(gè)類的更深入內(nèi)容,可以參閱《CLR Via C#》等相關(guān)書籍,這里就不再討論了。委托、事件與Observer設(shè)計(jì)模式
范例說明
上面的例子已不足以再進(jìn)行下面的講解了,我們來看一個(gè)新的范例,因?yàn)橹耙呀?jīng)介紹了很多的內(nèi)容,所以本節(jié)的進(jìn)度會(huì)稍微快一些:
假設(shè)我們有個(gè)高檔的熱水器,我們給它通上電,當(dāng)水溫超過95度的時(shí)候:
1、揚(yáng)聲器會(huì)開始發(fā)出語音,告訴你水的溫度;
2、液晶屏也會(huì)改變水溫的顯示,來提示水已經(jīng)快燒開了。
現(xiàn)在我們需要寫個(gè)程序來模擬這個(gè)燒水的過程,我們將定義一個(gè)類來代表熱水器,我們管它叫:Heater,它有代表水溫的字段,叫做temperature;當(dāng)然,還有必不可少的給水加熱方法BoilWater(),一個(gè)發(fā)出語音警報(bào)的方法MakeAlert(),一個(gè)顯示水溫的方法,ShowMsg()。
namespace Delegate { class Heater { private int temperature;// 水溫
// 燒水
public void BoilWater(){ for(int i = 0;i <= 100;i++){ temperature = i;
if(temperature > 95){ MakeAlert(temperature);ShowMsg(temperature);} } }
// 發(fā)出語音警報(bào)
private void MakeAlert(int param){ Console.WriteLine(“Alarm:嘀嘀嘀,水已經(jīng) {0} 度了:” , param);}
// 顯示水溫
private void ShowMsg(int param){ Console.WriteLine(“Display:水快開了,當(dāng)前溫度:{0}度?!?, param);} }
class Program { static void Main(){ Heater ht = new Heater();ht.BoilWater();} } }
Observer設(shè)計(jì)模式簡介
上面的例子顯然能完成我們之前描述的工作,但是卻并不夠好?,F(xiàn)在假設(shè)熱水器由三部分組成:熱水器、警報(bào)器、顯示器,它們來自于不同廠商并進(jìn)行了組裝。那么,應(yīng)該是熱水器僅僅負(fù)責(zé)燒水,它不能發(fā)出警報(bào)也不能顯示水溫;在水燒開時(shí)由警報(bào)器發(fā)出警報(bào)、顯示器顯示提示和水溫。
這時(shí)候,上面的例子就應(yīng)該變成這個(gè)樣子: // 熱水器
public class Heater { private int temperature;
// 燒水
private void BoilWater(){ for(int i = 0;i <= 100;i++){ temperature = i;} } }
// 警報(bào)器
public class Alarm{ private void MakeAlert(int param){ Console.WriteLine(“Alarm:嘀嘀嘀,水已經(jīng) {0} 度了:” , param);} }
// 顯示器
public class Display{ private void ShowMsg(int param){ Console.WriteLine(“Display:水已燒開,當(dāng)前溫度:{0}度?!?, param);} }
這里就出現(xiàn)了一個(gè)問題:如何在水燒開的時(shí)候通知報(bào)警器和顯示器?在繼續(xù)進(jìn)行之前,我們先了解一下Observer設(shè)計(jì)模式,Observer設(shè)計(jì)模式中主要包括如下兩類對象:
Subject:監(jiān)視對象,它往往包含著其他對象所感興趣的內(nèi)容。在本范例中,熱水器就是一個(gè)監(jiān)視對象,它包含的其他對象所感興趣的內(nèi)容,就是temprature字段,當(dāng)這個(gè)字段的值快到100時(shí),會(huì)不斷把數(shù)據(jù)發(fā)給監(jiān)視它的對象。
Observer:監(jiān)視者,它監(jiān)視Subject,當(dāng)Subject中的某件事發(fā)生的時(shí)候,會(huì)告知Observer,而Observer則會(huì)采取相應(yīng)的行動(dòng)。在本范例中,Observer有警報(bào)器和顯示器,它們采取的行動(dòng)分別是發(fā)出警報(bào)和顯示水溫。
在本例中,事情發(fā)生的順序應(yīng)該是這樣的:
1.警報(bào)器和顯示器告訴熱水器,它對它的溫度比較感興趣(注冊)。2.熱水器知道后保留對警報(bào)器和顯示器的引用。
3.熱水器進(jìn)行燒水這一動(dòng)作,當(dāng)水溫超過95度時(shí),通過對警報(bào)器和顯示器的引用,自動(dòng)調(diào)用警報(bào)器的MakeAlert()方法、顯示器的ShowMsg()方法。
類似這樣的例子是很多的,GOF對它進(jìn)行了抽象,稱為Observer設(shè)計(jì)模式:Observer設(shè)計(jì)模式是為了定義對象間的一種一對多的依賴關(guān)系,以便于當(dāng)一個(gè)對象的狀態(tài)改變時(shí),其他依賴于它的對象會(huì)被自動(dòng)告知并更新。Observer模式是一種松耦合的設(shè)計(jì)模式。實(shí)現(xiàn)范例的Observer設(shè)計(jì)模式
我們之前已經(jīng)對委托和事件介紹很多了,現(xiàn)在寫代碼應(yīng)該很容易了,現(xiàn)在在這里直接給出代碼,并在注釋中加以說明。
using System;using System.Collections.Generic;using System.Text;
namespace Delegate { // 熱水器
public class Heater { private int temperature;public delegate void BoilHandler(int param);//聲明委托 public event BoilHandler BoilEvent;//聲明事件
// 燒水
public void BoilWater(){ for(int i = 0;i <= 100;i++){ temperature = i;
if(temperature > 95){ if(BoilEvent!= null){ //如果有對象注冊
BoilEvent(temperature);//調(diào)用所有注冊對象的方法 } } } } }
// 警報(bào)器
public class Alarm { public void MakeAlert(int param){ Console.WriteLine(“Alarm:嘀嘀嘀,水已經(jīng) {0} 度了:”, param);} }
// 顯示器
public class Display { public static void ShowMsg(int param){ //靜態(tài)方法
Console.WriteLine(“Display:水快燒開了,當(dāng)前溫度:{0}度?!? param);} }
class Program { static void Main(){ Heater heater = new Heater();Alarm alarm = new Alarm();
heater.BoilEvent += alarm.MakeAlert;//注冊方法
heater.BoilEvent +=(new Alarm()).MakeAlert;//給匿名對象注冊方法 heater.BoilEvent += Display.ShowMsg;//注冊靜態(tài)方法
heater.BoilWater();//燒水,會(huì)自動(dòng)調(diào)用注冊過對象的方法 } } }
輸出為:
Alarm:嘀嘀嘀,水已經(jīng) 96 度了: Alarm:嘀嘀嘀,水已經(jīng) 96 度了: Display:水快燒開了,當(dāng)前溫度:96度。// 省略....Net Framework中的委托與事件
盡管上面的范例很好地完成了我們想要完成的工作,但是我們不僅疑惑:為什么.Net Framework 中的事件模型和上面的不同?為什么有很多的EventArgs參數(shù)?
在回答上面的問題之前,我們先搞懂.Net Framework的編碼規(guī)范:
1.委托類型的名稱都應(yīng)該以EventHandler結(jié)束。
2.委托的原型定義:有一個(gè)void返回值,并接受兩個(gè)輸入?yún)?shù):一個(gè)Object 類型,一個(gè) EventArgs類型(或繼承自EventArgs)。
3.事件的命名為 委托去掉 EventHandler之后剩余的部分。4.繼承自EventArgs的類型應(yīng)該以EventArgs結(jié)尾。
再做一下說明:
1.委托聲明原型中的Object類型的參數(shù)代表了Subject,也就是監(jiān)視對象,在本例中是 Heater(熱水器)。回調(diào)函數(shù)(比如Alarm的MakeAlert)可以通過它訪問觸發(fā)事件的對象(Heater)。
2.EventArgs 對象包含了Observer所感興趣的數(shù)據(jù),在本例中是temperature。
上面這些其實(shí)不僅僅是為了編碼規(guī)范而已,這樣也使得程序有更大的靈活性。比如說,如果我們不光想獲得熱水器的溫度,還想在Observer端(警報(bào)器或者顯示器)方法中獲得它的生產(chǎn)日期、型號(hào)、價(jià)格,那么委托和方法的聲明都會(huì)變得很麻煩,而如果我們將熱水器的引用傳給警報(bào)器的方法,就可以在方法中直接訪問熱水器了。
現(xiàn)在我們改寫之前的范例,讓它符合.Net Framework 的規(guī)范: using System;using System.Collections.Generic;using System.Text;
namespace Delegate { // 熱水器
public class Heater { private int temperature;public string type = “RealFire 001”;// 添加型號(hào)作為演示 public string area = “China Xian”;// 添加產(chǎn)地作為演示
//聲明委托
public delegate void BoiledEventHandler(Object sender, BoliedEventArgs e);public event BoiledEventHandler Boiled;//聲明事件
// 定義BoliedEventArgs類,傳遞給Observer所感興趣的信息 public class BoliedEventArgs : EventArgs { public readonly int temperature;public BoliedEventArgs(int temperature){ this.temperature = temperature;} }
// 可以供繼承自 Heater 的類重寫,以便繼承類拒絕其他對象對它的監(jiān)視 protected virtual void OnBolied(BoliedEventArgs e){ if(Boiled!= null){ // 如果有對象注冊
Boiled(this, e);// 調(diào)用所有注冊對象的方法 } }
// 燒水。
public void BoilWater(){ for(int i = 0;i <= 100;i++){ temperature = i;if(temperature > 95){ //建立BoliedEventArgs 對象。
BoliedEventArgs e = new BoliedEventArgs(temperature);OnBolied(e);// 調(diào)用 OnBolied方法 } } } }
// 警報(bào)器
public class Alarm { public void MakeAlert(Object sender, Heater.BoliedEventArgs e){ Heater heater =(Heater)sender;//這里是不是很熟悉呢? //訪問 sender 中的公共字段
Console.WriteLine(“Alarm:{0}{1}: ”, heater.area, heater.type);Console.WriteLine(“Display:水快燒開了,當(dāng)前溫度:{0}度?!? e.temperature);Console.WriteLine();} }
class Program { static void Main(){ Heater heater = new Heater();Alarm alarm = new Alarm();
heater.Boiled += alarm.MakeAlert;//注冊方法
heater.Boiled +=(new Alarm()).MakeAlert;//給匿名對象注冊方法
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert);//也可以這么注冊 heater.Boiled += Display.ShowMsg;//注冊靜態(tài)方法
heater.BoilWater();//燒水,會(huì)自動(dòng)調(diào)用注冊過對象的方法 } } }
輸出為:
Alarm:China XianRealFire 001: Alarm: 嘀嘀嘀,水已經(jīng) 96 度了: Alarm:China XianRealFire 001: Display:水快燒開了,當(dāng)前溫度:96度。// 省略...總結(jié)
在本文中我首先通過一個(gè)GreetingPeople的小程序向大家介紹了委托的概念、委托用來做什么,隨后又引出了事件,接著對委托與事件所產(chǎn)生的中間代碼做了粗略的講述。
在第二個(gè)稍微復(fù)雜點(diǎn)的熱水器的范例中,我向大家簡要介紹了 Observer設(shè)計(jì)模式,并通過實(shí)現(xiàn)這個(gè)范例完成了該模式,隨后講述了.Net Framework中委托、事件的實(shí)現(xiàn)方式。
本文的源碼可以在http://www.tracefact.net/sourcecode/delegates-and-events.rar 下載。