日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

[轉]C# 中的委托和事件

發(fā)布時(shí)間:2023/12/10 C# 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [轉]C# 中的委托和事件 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
轉(zhuǎn)自:http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html
pdf:http://www.tracefact.net/Document/Delegates-and-Events-in-CSharp.pdf

C# 中的委托和事件

引言

委托 和 事件在 .Net Framework中的應(yīng)用非常廣泛,然而,較好地理解委托和事件對(duì)很多接觸C#時(shí)間不長(zhǎng)的人來(lái)說(shuō)并不容易。它們就像是一道檻兒,過(guò)了這個(gè)檻的人,覺(jué)得真是太容易了,而沒(méi)有過(guò)去的人每次見到委托和事件就覺(jué)得心里別(biè)得慌,混身不自在。本文中,我將通過(guò)兩個(gè)范例由淺入深地講述什么是委托、為什么要使用委托、事件的由來(lái)、.Net Framework中的委托和事件、委托和事件對(duì)Observer設(shè)計(jì)模式的意義,對(duì)它們的中間代碼也做了討論。

將方法作為方法的參數(shù)

我們先不管這個(gè)標(biāo)題如何的繞口,也不管委托究竟是個(gè)什么東西,來(lái)看下面這兩個(gè)最簡(jiǎn)單的方法,它們不過(guò)是在屏幕上輸出一句問(wèn)候的話語(yǔ):

public void GreetPeople(string name) {
??? // 做某些額外的事情,比如初始化之類,此處略
??? EnglishGreeting(name);
}
public void EnglishGreeting(string name) {
??? Console.WriteLine("Morning, " + name);
}

暫且不管這兩個(gè)方法有沒(méi)有什么實(shí)際意義。GreetPeople用于向某人問(wèn)好,當(dāng)我們傳遞代表某人姓名的name參數(shù),比如說(shuō)“Jimmy”,進(jìn)去的時(shí)候,在這個(gè)方法中,將調(diào)用EnglishGreeting方法,再次傳遞name參數(shù),EnglishGreeting則用于向屏幕輸出 “Morning, Jimmy”。

現(xiàn)在假設(shè)這個(gè)程序需要進(jìn)行全球化,哎呀,不好了,我是中國(guó)人,我不明白“Morning”是什么意思,怎么辦呢?好吧,我們?cè)偌觽€(gè)中文版的問(wèn)候方法:

public void ChineseGreeting(string name){
??? Console.WriteLine("早上好, " + name);
}

這時(shí)候,GreetPeople也需要改一改了,不然如何判斷到底用哪個(gè)版本的Greeting問(wèn)候方法合適呢?在進(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,盡管這樣解決了問(wèn)題,但我不說(shuō)大家也很容易想到,這個(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)我們賦給它“張子陽(yáng)”時(shí),它又代表著“張子陽(yáng)”這個(gè)值。然后,我們可以在方法體內(nèi)對(duì)這個(gè)name進(jìn)行其他操作。哎,這簡(jiǎ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等)?然后,我們?cè)诜椒w內(nèi),也可以像使用別的參數(shù)一樣使用MakeGreeting。但是,由于MakeGreeting代表著一個(gè)方法,它的使用方式應(yīng)該和它被賦的方法(比如ChineseGreeting)是一樣的,比如:

MakeGreeting(name);

好了,有了思路了,我們現(xiàn)在就來(lái)改改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è)大問(wèn)題:這個(gè)代表著方法的MakeGreeting參數(shù)應(yīng)該是什么類型的?

NOTE:這里已不再需要枚舉了,因?yàn)樵诮oMakeGreeting賦值的時(shí)候動(dòng)態(tài)地決定使用哪個(gè)方法,是ChineseGreeting還是 EnglishGreeting,而在這個(gè)兩個(gè)方法內(nèi)部,已經(jīng)對(duì)使用“morning”還是“早上好”作了區(qū)分。

聰明的你應(yīng)該已經(jīng)想到了,現(xiàn)在是委托該出場(chǎng)的時(shí)候了,但講述委托之前,我們?cè)倏纯碝akeGreeting參數(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()方法的簽名對(duì)比一下,除了加入了delegate關(guān)鍵字以外,其余的是不是完全一樣?

現(xiàn)在,讓我們?cè)俅胃膭?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)在,請(qǐng)看看這個(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("張子陽(yáng)", ChineseGreeting);
??? ?????????? Console.ReadKey();
?????? ??? }
??? ??? }
??? }

輸出如下:
Morning, Jimmy Zhang
早上好, 張子陽(yáng)

我們現(xiàn)在對(duì)委托做一個(gè)總結(jié):

委托是一個(gè)類,它定義了方法的類型,使得可以將方法當(dāng)作另一個(gè)方法的參數(shù)來(lái)進(jìn)行傳遞,這種將方法動(dòng)態(tài)地賦給參數(shù)的做法,可以避免在程序中大量使用If-Else(Switch)語(yǔ)句,同時(shí)使得程序具有更好的可擴(kuò)展性。

將方法綁定到委托

看到這里,是不是有那么點(diǎn)如夢(mèng)初醒的感覺(jué)?于是,你是不是在想:在上面的例子中,我不一定要直接在GreetPeople()方法中給 name參數(shù)賦值,我可以像這樣使用變量:

static void Main(string[] args) {
??? string name1, name2;
??? name1 = "Jimmy Zhang";
??? name2 = "張子陽(yáng)";

???? 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("張子陽(yáng)", delegate2);
??? ??? Console.ReadKey();
}

如你所料,這樣是沒(méi)有問(wèn)題的,程序一如預(yù)料的那樣輸出。這里,我想說(shuō)的是委托不同于string的一個(gè)特性:可以將多個(gè)方法賦給同一個(gè)委托,或者叫將多個(gè)方法綁定到同一個(gè)委托,當(dāng)調(diào)用這個(gè)委托的時(shí)候,將依次調(diào)用其所綁定的方法。在這個(gè)例子中,語(yǔ)法如下:

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í)際上,我們可以也可以繞過(guò)GreetPeople方法,通過(guò)委托來(lái)直接調(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:這在本例中是沒(méi)有問(wèn)題的,但回頭看下上面GreetPeople()的定義,在它之中可以做一些對(duì)于EnglshihGreeting和ChineseGreeting來(lái)說(shuō)都需要進(jìn)行的工作,為了簡(jiǎn)便我做了省略。

注意這里,第一次用的“=”,是賦值的語(yǔ)法;第二次,用的是“+=”,是綁定的語(yǔ)法。如果第一次就使用“+=”,將出現(xiàn)“使用了未賦值的局部變量”的編譯錯(cuò)誤。

我們也可以使用下面的代碼來(lái)這樣簡(jiǎn)化這一過(guò)程:

GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
delegate1 += ChineseGreeting;?? // 給此委托變量再綁定一個(gè)方法

看到這里,應(yīng)該注意到,這段代碼第一條語(yǔ)句與實(shí)例化一個(gè)類是何其的相似,你不禁想到:上面第一次綁定委托時(shí)不可以使用“+=”的編譯錯(cuò)誤,或許可以用這樣的方法來(lái)避免:

GreetingDelegate delegate1 = new GreetingDelegate();
delegate1 += EnglishGreeting;?? // 這次用的是 “+=”,綁定語(yǔ)法。
delegate1 += ChineseGreeting;?? // 給此委托變量再綁定一個(gè)方法

但實(shí)際上,這樣會(huì)出現(xiàn)編譯錯(cuò)誤: “GreetingDelegate”方法沒(méi)有采用“0”個(gè)參數(shù)的重載。盡管這樣的結(jié)果讓我們覺(jué)得有點(diǎn)沮喪,但是編譯的提示:“沒(méi)有0個(gè)參數(shù)的重載”再次讓我們聯(lián)想到了類的構(gòu)造函數(shù)。我知道你一定按捺不住想探個(gè)究竟,但再此之前,我們需要先把基礎(chǔ)知識(shí)和應(yīng)用介紹完。

既然給委托可以綁定一個(gè)方法,那么也應(yīng)該有辦法取消對(duì)方法的綁定,很容易想到,這個(gè)語(yǔ)法是“-=”:

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; //取消對(duì)EnglishGreeting方法的綁定
??? // 將僅調(diào)用 ChineseGreeting
??? GreetPeople("張子陽(yáng)", delegate1);
??? Console.ReadKey();
}
輸出為:
Morning, Jimmy Zhang
早上好, Jimmy Zhang
早上好, 張子陽(yáng)

讓我們?cè)俅螌?duì)委托作個(gè)總結(jié):

使用委托可以將多個(gè)方法綁定到同一個(gè)委托變量,當(dāng)調(diào)用此變量時(shí)(這里用“調(diào)用”這個(gè)詞,是因?yàn)榇俗兞看硪粋€(gè)方法),可以依次調(diào)用所有綁定的方法。

事件的由來(lái)

我們繼續(xù)思考上面的程序:上面的三個(gè)方法都定義在Programe類中,這樣做是為了理解的方便,實(shí)際應(yīng)用中,通常都是 GreetPeople 在一個(gè)類中,ChineseGreeting和 EnglishGreeting 在另外的類中。現(xiàn)在你已經(jīng)對(duì)委托有了初步了解,是時(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("張子陽(yáng)", ChineseGreeting);
}

我們運(yùn)行這段代碼,嗯,沒(méi)有任何問(wèn)題。程序一如預(yù)料地那樣輸出了:

Morning, Jimmy Zhang

早上好, 張子陽(yáng)

現(xiàn)在,假設(shè)我們需要使用上一節(jié)學(xué)到的知識(shí),將多個(gè)方法綁定到同一個(gè)委托變量,該如何做呢?讓我們?cè)俅胃膶懘a:

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ì),講究的是對(duì)象的封裝,既然可以聲明委托類型的變量(在上例中是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);
}

輸出為:
Morning, Jimmy Zhang
早上好, Jimmy Zhang

盡管這樣做沒(méi)有任何問(wèn)題,但我們發(fā)現(xiàn)這條語(yǔ)句很奇怪。在調(diào)用gm.GreetPeople方法的時(shí)候,再次傳遞了gm的delegate1字段:

gm.GreetPeople("Jimmy Zhang", gm.delegate1);

既然如此,我們何不修改 GreetingManager 類成這樣:

public class GreetingManager{
??? //在GreetingManager類的內(nèi)部聲明delegate1變量
??? public GreetingDelegate delegate1;?

??? public void GreetPeople(string name) {
??? ??? if(delegate1!=null){???? //如果有方法注冊(cè)委托變量
?? ?????? delegate1(name);????? //通過(guò)委托調(diào)用方法
?????? }
??? }
}

在客戶端,調(diào)用看上去更簡(jiǎn)潔一些:

static void Main(string[] args) {
??? GreetingManager gm = new? GreetingManager();
??? gm.delegate1 = EnglishGreeting;
??? gm.delegate1 += ChineseGreeting;

??? gm.GreetPeople("Jimmy Zhang");????? //注意,這次不需要再傳遞 delegate1變量
}

輸出為:
Morning, Jimmy Zhang
早上好, Jimmy Zhang

盡管這樣達(dá)到了我們要的效果,但是還是存在著問(wèn)題:

在這里,delegate1和我們平時(shí)用的string類型的變量沒(méi)有什么分別,而我們知道,并不是所有的字段都應(yīng)該聲明成public,合適的做法是應(yīng)該public的時(shí)候public,應(yīng)該private的時(shí)候private。

我們先看看如果把 delegate1 聲明為 private會(huì)怎樣?結(jié)果就是:這簡(jiǎn)直就是在搞笑。因?yàn)槁暶魑械哪康木褪菫榱税阉┞对陬惖目蛻舳诉M(jìn)行方法的注冊(cè),你把它聲明為private了,客戶端對(duì)它根本就不可見,那它還有什么用?

再看看把delegate1 聲明為 public 會(huì)怎樣?結(jié)果就是:在客戶端可以對(duì)它進(jìn)行隨意的賦值等操作,嚴(yán)重破壞對(duì)象的封裝性。

最后,第一個(gè)方法注冊(cè)用“=”,是賦值語(yǔ)法,因?yàn)橐M(jìn)行實(shí)例化,第二個(gè)方法注冊(cè)則用的是“+=”。但是,不管是賦值還是注冊(cè),都是將方法綁定到委托上,除了調(diào)用時(shí)先后順序不同,再?zèng)]有任何的分別,這樣不是讓人覺(jué)得很別扭么?

現(xiàn)在我們想想,如果delegate1不是一個(gè)委托類型,而是一個(gè)string類型,你會(huì)怎么做?答案是使用屬性對(duì)字段進(jìn)行封裝。

于是,Event出場(chǎng)了,它封裝了委托類型的變量,使得:在類的內(nèi)部,不管你聲明它是public還是protected,它總是private的。在類的外部,注冊(cè)“+=”和注銷“-=”的訪問(wèn)限定符與你在聲明事件時(shí)使用的訪問(wèn)符相同。

我們改寫GreetingManager類,它變成了這個(gè)樣子:

public class GreetingManager{
??? //這一次我們?cè)谶@里聲明一個(gè)事件
??? public event GreetingDelegate MakeGreet;

??? public void GreetPeople(string name) {
??? ??? MakeGreet(name);
??? }
}

很容易注意到:MakeGreet 事件的聲明與之前委托變量delegate1的聲明唯一的區(qū)別是多了一個(gè)event關(guān)鍵字。看到這里,在結(jié)合上面的講解,你應(yīng)該明白到:事件其實(shí)沒(méi)什么不好理解的,聲明一個(gè)事件不過(guò)類似于聲明一個(gè)進(jìn)行了封裝的委托類型的變量而已。

為了證明上面的推論,如果我們像下面這樣改寫Main方法:

static void Main(string[] args) {
??? GreetingManager gm = new? GreetingManager();
??? gm.MakeGreet = EnglishGreeting;???????? // 編譯錯(cuò)誤1
??? gm.MakeGreet += ChineseGreeting;

??? gm.GreetPeople("Jimmy Zhang");
}

會(huì)得到編譯錯(cuò)誤:事件“Delegate.GreetingManager.MakeGreet”只能出現(xiàn)在 += 或 -= 的左邊(從類型“Delegate.GreetingManager”中使用時(shí)除外)。

事件和委托的編譯代碼

這時(shí)候,我們注釋掉編譯錯(cuò)誤的行,然后重新進(jìn)行編譯,再借助Reflactor來(lái)對(duì) event的聲明語(yǔ)句做一探究,看看為什么會(huì)發(fā)生這樣的錯(cuò)誤:

public event GreetingDelegate MakeGreet;

可以看到,實(shí)際上盡管我們?cè)贕reetingManager里將 MakeGreet 聲明為public,但是,實(shí)際上MakeGreet會(huì)被編譯成 私有字段,難怪會(huì)發(fā)生上面的編譯錯(cuò)誤了,因?yàn)樗揪筒辉试S在GreetingManager類的外面以賦值的方式訪問(wèn),從而驗(yàn)證了我們上面所做的推論。

我們?cè)龠M(jìn)一步看下MakeGreet所產(chǎn)生的代碼:

private GreetingDelegate MakeGreet; //對(duì)事件的聲明 實(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類型的委托,只不過(guò)不管是不是聲明為public,它總是被聲明為private。另外,它還有兩個(gè)方法,分別是add_MakeGreet和remove_MakeGreet,這兩個(gè)方法分別用于注冊(cè)委托類型的方法和取消注冊(cè)。實(shí)際上也就是: “+= ”對(duì)應(yīng) add_MakeGreet,“-=”對(duì)應(yīng)remove_MakeGreet。而這兩個(gè)方法的訪問(wèn)限制取決于聲明事件時(shí)的訪問(wèn)限制符。

在add_MakeGreet()方法內(nèi)部,實(shí)際上調(diào)用了System.Delegate的Combine()靜態(tài)方法,這個(gè)方法用于將當(dāng)前的變量添加到委托鏈表中。我們前面提到過(guò)兩次,說(shuō)委托實(shí)際上是一個(gè)類,在我們定義委托的時(shí)候:

public delegate void GreetingDelegate(string name);

當(dāng)編譯器遇到這段代碼的時(shí)候,會(huì)生成下面這樣一個(gè)完整的類:

public sealed 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ì)模式

范例說(shuō)明

上面的例子已不足以再進(jìn)行下面的講解了,我們來(lái)看一個(gè)新的范例,因?yàn)橹耙呀?jīng)介紹了很多的內(nèi)容,所以本節(jié)的進(jìn)度會(huì)稍微快一些:

假設(shè)我們有個(gè)高檔的熱水器,我們給它通上電,當(dāng)水溫超過(guò)95度的時(shí)候:1、揚(yáng)聲器會(huì)開始發(fā)出語(yǔ)音,告訴你水的溫度;2、液晶屏也會(huì)改變水溫的顯示,來(lái)提示水已經(jīng)快燒開了。

現(xiàn)在我們需要寫個(gè)程序來(lái)模擬這個(gè)燒水的過(guò)程,我們將定義一個(gè)類來(lái)代表熱水器,我們管它叫:Heater,它有代表水溫的字段,叫做temperature;當(dāng)然,還有必不可少的給水加熱方法BoilWater(),一個(gè)發(fā)出語(yǔ)音警報(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ā)出語(yǔ)音警報(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ì)模式簡(jiǎn)介

上面的例子顯然能完成我們之前描述的工作,但是卻并不夠好。現(xiàn)在假設(shè)熱水器由三部分組成:熱水器、警報(bào)器、顯示器,它們來(lái)自于不同廠商并進(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è)問(wèn)題:如何在水燒開的時(shí)候通知報(bào)警器和顯示器?在繼續(xù)進(jìn)行之前,我們先了解一下Observer設(shè)計(jì)模式,Observer設(shè)計(jì)模式中主要包括如下兩類對(duì)象:

  • Subject:監(jiān)視對(duì)象,它往往包含著其他對(duì)象所感興趣的內(nèi)容。在本范例中,熱水器就是一個(gè)監(jiān)視對(duì)象,它包含的其他對(duì)象所感興趣的內(nèi)容,就是temprature字段,當(dāng)這個(gè)字段的值快到100時(shí),會(huì)不斷把數(shù)據(jù)發(fā)給監(jiān)視它的對(duì)象。
  • 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)該是這樣的:

  • 警報(bào)器和顯示器告訴熱水器,它對(duì)它的溫度比較感興趣(注冊(cè))。
  • 熱水器知道后保留對(duì)警報(bào)器和顯示器的引用。
  • 熱水器進(jìn)行燒水這一動(dòng)作,當(dāng)水溫超過(guò)95度時(shí),通過(guò)對(duì)警報(bào)器和顯示器的引用,自動(dòng)調(diào)用警報(bào)器的MakeAlert()方法、顯示器的ShowMsg()方法。
  • 類似這樣的例子是很多的,GOF對(duì)它進(jìn)行了抽象,稱為Observer設(shè)計(jì)模式:Observer設(shè)計(jì)模式是為了定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,以便于當(dāng)一個(gè)對(duì)象的狀態(tài)改變時(shí),其他依賴于它的對(duì)象會(huì)被自動(dòng)告知并更新。Observer模式是一種松耦合的設(shè)計(jì)模式。

    實(shí)現(xiàn)范例的Observer設(shè)計(jì)模式

    我們之前已經(jīng)對(duì)委托和事件介紹很多了,現(xiàn)在寫代碼應(yīng)該很容易了,現(xiàn)在在這里直接給出代碼,并在注釋中加以說(shuō)明。

    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) { //如果有對(duì)象注冊(cè)
    ????????????????????? BoilEvent(temperature);? //調(diào)用所有注冊(cè)對(duì)象的方法
    ????????????????? }
    ????????????? }
    ?????????? }
    ?????? }
    ??? }

    ??? // 警報(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;??? //注冊(cè)方法
    ?????????? heater.BoilEvent += (new Alarm()).MakeAlert;?? //給匿名對(duì)象注冊(cè)方法
    ?????????? heater.BoilEvent += Display.ShowMsg;?????? //注冊(cè)靜態(tài)方法

    ?????????? heater.BoilWater();?? //燒水,會(huì)自動(dòng)調(diào)用注冊(cè)過(guò)對(duì)象的方法
    ?????? }
    ??? }
    }
    輸出為:
    Alarm:嘀嘀嘀,水已經(jīng) 96 度了:
    Alarm:嘀嘀嘀,水已經(jīng) 96 度了:
    Display:水快燒開了,當(dāng)前溫度:96度。
    // 省略...

    .Net Framework中的委托與事件

    盡管上面的范例很好地完成了我們想要完成的工作,但是我們不僅疑惑:為什么.Net Framework 中的事件模型和上面的不同?為什么有很多的EventArgs參數(shù)?

    在回答上面的問(wèn)題之前,我們先搞懂 .Net Framework的編碼規(guī)范:

    • 委托類型的名稱都應(yīng)該以EventHandler結(jié)束。
    • 委托的原型定義:有一個(gè)void返回值,并接受兩個(gè)輸入?yún)?shù):一個(gè)Object 類型,一個(gè) EventArgs類型(或繼承自EventArgs)。
    • 事件的命名為 委托去掉 EventHandler之后剩余的部分。
    • 繼承自EventArgs的類型應(yīng)該以EventArgs結(jié)尾。

    再做一下說(shuō)明:

  • 委托聲明原型中的Object類型的參數(shù)代表了Subject,也就是監(jiān)視對(duì)象,在本例中是 Heater(熱水器)。回調(diào)函數(shù)(比如Alarm的MakeAlert)可以通過(guò)它訪問(wèn)觸發(fā)事件的對(duì)象(Heater)。
  • EventArgs 對(duì)象包含了Observer所感興趣的數(shù)據(jù),在本例中是temperature。
  • 上面這些其實(shí)不僅僅是為了編碼規(guī)范而已,這樣也使得程序有更大的靈活性。比如說(shuō),如果我們不光想獲得熱水器的溫度,還想在Observer端(警報(bào)器或者顯示器)方法中獲得它的生產(chǎn)日期、型號(hào)、價(jià)格,那么委托和方法的聲明都會(huì)變得很麻煩,而如果我們將熱水器的引用傳給警報(bào)器的方法,就可以在方法中直接訪問(wèn)熱水器了。

    現(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, BoiledEventArgs e);
    ?????? public event BoiledEventHandler Boiled; //聲明事件

    ?????? // 定義BoiledEventArgs類,傳遞給Observer所感興趣的信息
    ?????? public class BoiledEventArgs : EventArgs {
    ?????????? public readonly int temperature;
    ?????????? public BoiledEventArgs(int temperature) {
    ????????????? this.temperature = temperature;
    ?????????? }
    ?????? }

    ?????? // 可以供繼承自 Heater 的類重寫,以便繼承類拒絕其他對(duì)象對(duì)它的監(jiān)視
    ?????? protected virtual void OnBoiled(BoiledEventArgs e) {
    ?????????? if (Boiled != null) { // 如果有對(duì)象注冊(cè)
    ????????????? Boiled(this, e);? // 調(diào)用所有注冊(cè)對(duì)象的方法
    ?????????? }
    ?????? }
    ??????
    ?????? // 燒水。
    ?????? public void BoilWater() {
    ?????????? for (int i = 0; i <= 100; i++) {
    ????????????? temperature = i;
    ????????????? if (temperature > 95) {
    ????????????????? //建立BoiledEventArgs 對(duì)象。
    ????????????????? BoiledEventArgs e = new BoiledEventArgs(temperature);
    ????????????????? OnBoiled(e);? // 調(diào)用 OnBolied方法
    ????????????? }
    ?????????? }
    ?????? }
    ??? }

    ??? // 警報(bào)器
    ??? public class Alarm {
    ?????? public void MakeAlert(Object sender, Heater.BoiledEventArgs e) {
    ?????????? Heater heater = (Heater)sender;???? //這里是不是很熟悉呢?
    ?????????? //訪問(wèn) sender 中的公共字段
    ?????????? Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
    ?????????? Console.WriteLine("Alarm: 嘀嘀嘀,水已經(jīng) {0} 度了:", e.temperature);
    ?????????? Console.WriteLine();
    ?????? }
    ??? }

    ??? // 顯示器
    ??? public class Display {
    ?????? public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) {?? //靜態(tài)方法
    ?????????? Heater heater = (Heater)sender;
    ?????????? Console.WriteLine("Display:{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;?? //注冊(cè)方法
    ?????????? heater.Boiled += (new Alarm()).MakeAlert;????? //給匿名對(duì)象注冊(cè)方法
    ?????????? heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert);??? //也可以這么注冊(cè)
    ?????????? heater.Boiled += Display.ShowMsg;?????? //注冊(cè)靜態(tài)方法

    ?????????? heater.BoilWater();?? //燒水,會(huì)自動(dòng)調(diào)用注冊(cè)過(guò)對(duì)象的方法
    ?????? }
    ??? }
    }

    輸出為:
    Alarm:China Xian - RealFire 001:
    Alarm: 嘀嘀嘀,水已經(jīng) 96 度了:
    Alarm:China Xian - RealFire 001:
    Alarm: 嘀嘀嘀,水已經(jīng) 96 度了:
    Alarm:China Xian - RealFire 001:
    Alarm: 嘀嘀嘀,水已經(jīng) 96 度了:
    Display:China Xian - RealFire 001:
    Display:水快燒開了,當(dāng)前溫度:96度。
    // 省略 ...

    總結(jié)

    在本文中我首先通過(guò)一個(gè)GreetingPeople的小程序向大家介紹了委托的概念、委托用來(lái)做什么,隨后又引出了事件,接著對(duì)委托與事件所產(chǎn)生的中間代碼做了粗略的講述。

    在第二個(gè)稍微復(fù)雜點(diǎn)的熱水器的范例中,我向大家簡(jiǎn)要介紹了 Observer設(shè)計(jì)模式,并通過(guò)實(shí)現(xiàn)這個(gè)范例完成了該模式,隨后講述了.Net Framework中委托、事件的實(shí)現(xiàn)方式。

    希望這篇文章能給你帶來(lái)幫助。

    轉(zhuǎn)載于:https://www.cnblogs.com/Athrun/archive/2009/07/20/1527365.html

    總結(jié)

    以上是生活随笔為你收集整理的[轉]C# 中的委托和事件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    婷婷色中文 | 天天激情综合 | www.一区二区三区 | 色偷偷88欧美精品久久久 | 国产小视频福利在线 | 国产精品久久99综合免费观看尤物 | 中文字幕有码在线播放 | 我要色综合天天 | 91丨九色丨丝袜 | 91亚洲精品久久久蜜桃 | 黄色软件在线观看 | 日韩高清一区二区 | 久草在线视频新 | 成人一区二区三区在线观看 | 黄色成人免费电影 | 特级西西www44高清大胆图片 | 日本福利视频在线 | 91最新地址永久入口 | 国产亚洲字幕 | 亚洲理论片在线观看 | av三级在线免费观看 | 成人黄视频 | 国产精品一区在线 | 日韩在线免费电影 | 国模精品一区二区三区 | 色婷婷激情综合 | 亚洲一区二区三区四区精品 | 免费视频97 | 在线免费黄色av | 午夜久久久久久久 | 日本电影久久 | 最近中文字幕国语免费高清6 | 日韩动漫免费观看高清完整版在线观看 | 色综合天天 | 国产手机视频在线播放 | 在线不卡视频 | 黄色中文字幕在线 | 久久99久久99精品中文字幕 | 色综合五月天 | 日本激情视频中文字幕 | 成人蜜桃网 | 欧美伦理一区 | 人人精品 | 免费黄色av电影 | 97干com| 人人狠 | 99精品在线观看视频 | 高清国产一区 | 免费日韩高清 | 色网站在线免费观看 | 免费亚洲黄色 | 高清日韩一区二区 | 一本一本久久a久久精品综合小说 | 精品国产自在精品国产精野外直播 | 国产日韩视频在线 | 久久精品国产免费观看 | 91精品国产99久久久久 | 久久久久国产成人精品亚洲午夜 | 国产精品久久嫩一区二区免费 | 亚洲欧美成人网 | 高清一区二区三区av | 精品91久久久久 | 久久免费一级片 | 99久久久国产精品免费观看 | 国产偷v国产偷∨精品视频 在线草 | 不卡电影一区二区三区 | 日韩中文字幕91 | avav99| 欧美十八 | 91亚洲精品国产 | 91在线网站 | 黄色亚洲大片免费在线观看 | 国产精品视频免费在线观看 | 国产精品理论视频 | 国内视频在线观看 | 超碰国产在线播放 | 日韩三级视频 | 久久天天躁 | 91九色porn在线资源 | 国产精品久久99精品毛片三a | 欧美视频99 | 成人av中文字幕在线观看 | 成年人国产在线观看 | 天堂久久电影网 | 亚洲在线不卡 | 国产成人一区二区在线观看 | 国产视频在线免费 | 久草香蕉在线视频 | 最新中文在线视频 | 日本一区二区三区视频在线播放 | 久精品视频在线 | 综合色中色 | 国内久久精品视频 | 亚洲成人免费观看 | 免费成人av | 天天干夜夜操视频 | 日韩午夜视频在线观看 | 最近中文字幕大全 | 97人人模人人爽人人喊中文字 | 亚洲高清在线观看视频 | 四虎免费av | 狠狠干狠狠艹 | 国产小视频免费在线网址 | 国产va在线| 天堂av网在线 | 欧美一级性生活视频 | 九色91福利 | 丝袜网站在线观看 | 国产精品99久久久精品免费观看 | 干天天| 在线观看日本韩国电影 | 五月天六月婷婷 | 国产视频精品在线 | 在线观看成人小视频 | 安徽妇搡bbbb搡bbbb | 国产中文字幕在线视频 | 91久久偷偷做嫩草影院 | 国产免费作爱视频 | 国产黄在线免费观看 | 国产在线观看免费观看 | 在线看黄网站 | 中文av日韩 | 天天操天天摸天天爽 | 欧美人牲| av网址最新 | 日韩色在线观看 | 久久精品超碰 | 五月婷婷亚洲 | 国产综合婷婷 | 亚州精品一二三区 | 精品国产乱码久久久久久三级人 | 国产欧美综合在线观看 | 欧美日韩视频 | 韩国av三级| 特级西西444www大胆高清无视频 | 美女搞黄国产视频网站 | 国产精品高 | 操天天操| 成人免费中文字幕 | 久久视频 | 高清久久久久久 | 国产精品免费视频一区二区 | 亚洲经典视频 | 欧美一级专区免费大片 | 国产高清在线免费视频 | 天堂视频中文在线 | 亚洲天堂精品视频 | 香蕉在线视频播放网站 | 亚洲视频在线免费看 | 国产精品久久片 | 精品国产欧美一区二区三区不卡 | 综合色伊人 | 一级黄色片网站 | 综合网中文字幕 | 日韩精品首页 | 欧美亚洲成人xxx | 成人av资源网站 | 成人黄色小说视频 | 成 人 黄 色 视频 免费观看 | 成年人黄色大全 | 免费观看全黄做爰大片国产 | 久久99久国产精品黄毛片入口 | 91精品人成在线观看 | 精品久久久久久亚洲 | 在线免费观看羞羞视频 | 九九九毛片 | 人人天天夜夜 | 在线日本看片免费人成视久网 | 天天射色综合 | 欧美最猛性xxxxx免费 | 国产亲近乱来精品 | 久精品视频在线观看 | 一区二区三区免费在线观看 | 亚洲国产成人精品电影在线观看 | 人人超碰免费 | 久久国产精品一区二区三区四区 | 国产精品中文字幕av | 人人藻人人澡人人爽 | av黄色影院 | 亚洲一区视频在线播放 | 亚洲日韩中文字幕在线播放 | 国产一区视频在线观看免费 | 欧美日韩高清 | 久久精品女人毛片国产 | 亚洲色影爱久久精品 | 色播亚洲婷婷 | 九九爱免费视频 | 久久艹艹 | 久久公开视频 | 婷婷丁香六月 | 国产日韩精品在线观看 | 日日夜夜人人精品 | 久草在线费播放视频 | 亚洲成a人片77777kkkk1在线观看 | av网址aaa | 日韩精品欧美专区 | 欧美午夜久久久 | 91chinesexxx| 欧美精品午夜 | 欧美色图一区 | 一区二区中文字幕在线播放 | 成人亚洲精品久久久久 | 午夜精品视频免费在线观看 | 欧美一级欧美一级 | 高清免费av在线 | 久久久久久免费毛片精品 | av成人动漫在线观看 | 成人久久免费视频 | 91在线色| 久久极品| 91高清免费观看 | 国产精品麻豆视频 | 人人看97 | 永久精品视频 | 久久dvd | 日操操| 97超碰资源站 | av成人免费在线观看 | 九九影视理伦片 | 波多野结衣视频一区二区三区 | 91桃花视频 | 五月天激情视频在线观看 | 国产精品毛片久久 | 国产专区在线视频 | 久久av中文字幕片 | 欧美一区免费观看 | 高清在线一区二区 | 免费在线观看毛片网站 | 99久久久久成人国产免费 | 麻豆免费观看视频 | 九九热久久久 | 久久欧美视频 | 成人在线观看日韩 | 激情五月亚洲 | 亚洲精品国偷拍自产在线观看 | 日韩一级电影网站 | 精品一区二区三区久久久 | 婷婷国产精品 | 国产中文字幕国产 | 制服丝袜一区二区 | 色悠悠久久综合 | 99久久精品视频免费 | 黄色aa久久| 在线三级av | 国产亚洲精品无 | 国产精品一区二区免费看 | 日韩午夜电影网 | 日韩欧美在线国产 | 成人蜜桃| 狠狠干网| 国产99久久99热这里精品5 | 日韩理论片中文字幕 | 在线观看aa | 欧美一级专区免费大片 | 国产成人99av超碰超爽 | 国产伦理久久精品久久久久_ | 久久久久久久久久久久av | 精品视频不卡 | 美腿丝袜一区二区三区 | 久久艹久久 | 成人小视频在线播放 | 精品欧美在线视频 | 亚洲国产精久久久久久久 | 久久久久久久久福利 | 日韩性色 | 久久国产乱 | 午夜国产福利在线 | 深爱激情五月网 | 91x色 | 久青草国产在线 | 国产在线p | 亚洲砖区区免费 | 91大神精品视频在线观看 | av久久在线 | 国产精品久久久久一区二区 | 欧美日韩一区二区三区视频 | 亚洲欧洲精品视频 | www亚洲一区 | 中文字幕在线免费观看视频 | japanese黑人亚洲人4k | 天天操偷偷干 | 国产精品一区在线观看你懂的 | 国产精品一区二区你懂的 | 五月婷婷在线综合 | 超碰免费观看 | 欧洲一区二区在线观看 | 91麻豆视频网站 | 国产黄色一级片 | 欧洲性视频 | 久青草电影 | 亚洲精品99久久久久久 | 婷婷综合亚洲 | 超碰97人人射妻 | 日产av在线播放 | 国产正在播放 | 欧美va在线观看 | 久久成人黄色 | 国产精品久久久久久久久久久久冷 | 偷拍久久久 | 精品久久久久久国产 | 91精品国产91久久久久福利 | 在线小视频国产 | 国产又粗又猛又爽又黄的视频先 | 色久天| 国产精品女同一区二区三区久久夜 | 麻豆综合网 | 超碰电影在线观看 | 久久成人毛片 | 婷婷丁香av | 亚洲精品久久久久中文字幕二区 | 欧美在线一二 | 在线观看黄a | 国产精品九九视频 | 国产1区2区3区精品美女 | 干干干操操操 | 天天干中文字幕 | 国产免费成人 | 日日日日日 | 夜夜夜夜操 | 在线一区观看 | 久草在线久 | 欧美大片在线观看一区 | 福利一区二区在线 | 国产精品五月天 | 免费能看的av | 天天操天天舔天天干 | 国产亚洲精品美女久久 | 亚洲欧美色婷婷 | 在线观看av网 | 美女网站在线观看 | 天天综合网国产 | 国产精品99久久免费观看 | 欧美色图东方 | www视频免费在线观看 | 国产 亚洲 欧美 在线 | 免费福利在线 | 久久成人午夜视频 | 日韩中文字幕在线 | 黄色av电影一级片 | 国产不卡在线看 | 综合久久久 | 中文字幕在线观看免费 | 丁香六月激情 | 日韩系列在线观看 | 亚洲丝袜中文 | 欧美性生活久久 | 九九色视频 | 免费毛片一区二区三区久久久 | av大全在线免费观看 | www看片网站 | 精品国产乱码 | 黄色片软件网站 | 日本中文字幕在线 | 久久久久一区二区三区四区 | 丁香六月国产 | 免费在线观看亚洲视频 | 色多视频在线观看 | 日韩视频免费看 | 日韩激情视频 | 91精品少妇偷拍99 | 天天干夜夜操视频 | 91完整版在线观看 | 色天堂在线视频 | 亚洲区视频在线观看 | 亚洲精品在线观看的 | 国内精品亚洲 | 热久在线 | 欧美激情视频一区 | 国产精品第二页 | 欧美精品久久久久 | 色婷婷福利视频 | 手机av看片 | www国产在线 | 天天人人 | 日本久久久久久久久久久 | 亚洲精品毛片一级91精品 | 中文字幕你懂的 | 福利一区二区三区四区 | 在线看国产一区 | 成人毛片100免费观看 | 奇米影视777四色米奇影院 | 久久国产精品视频观看 | 久久婷亚洲五月一区天天躁 | 欧美在线一二 | 国产精品激情偷乱一区二区∴ | 亚洲网久久 | 久久精品欧美日韩精品 | 国产涩涩在线观看 | 国产成人精品一区二区三区福利 | 久久久精品国产免费观看一区二区 | 成人av片免费看 | www.成人久久 | 亚洲国产成人精品在线 | www.久久99| 中文字幕在线免费播放 | 中文字幕丝袜美腿 | av网站在线观看免费 | 精品国偷自产国产一区 | 午夜av不卡 | 亚洲视频一区二区三区在线观看 | 国产亚洲婷婷免费 | 日韩欧美综合视频 | 五月天综合色激情 | 久久久久夜色 | 最近日本韩国中文字幕 | 亚洲第一区在线播放 | 超碰97在线资源 | 中文字幕av一区二区三区四区 | 丁香婷婷深情五月亚洲 | 超碰人人做 | 精品国产乱码一区二区三区在线 | 一区二区三区四区免费视频 | 亚洲国产中文字幕在线观看 | 日韩婷婷 | av在线网站大全 | 国产99久久精品一区二区300 | 在线免费91| 99久久婷婷国产一区二区三区 | 欧美日本高清视频 | www.久久99| 午夜精品久久久久久久99热影院 | 天天射天天干天天插 | 国产人成在线视频 | 337p日本大胆噜噜噜噜 | 这里只有精品视频在线 | 欧美成人影音 | 久草青青在线观看 | 香蕉视频久久久 | 免费看国产黄色 | 亚洲欧洲精品一区 | 99久久国产免费免费 | 久久久久欠精品国产毛片国产毛生 | 99热.com| 久久精品免费电影 | 国产精品毛片 | 在线观看国产日韩欧美 | 欧美极度另类 | 在线观看中文字幕亚洲 | 成人免费在线观看入口 | 国产午夜精品久久久久久久久久 | 欧美91精品久久久久国产性生爱 | 二区视频在线观看 | 午夜精品久久久 | 9免费视频 | 久久久亚洲电影 | 国产a国产a国产a | 国产专区第一页 | 久久综合久久久久88 | 中文字幕人成乱码在线观看 | 91麻豆文化传媒在线观看 | 狠狠久久伊人 | 国产成人一二三 | 午夜狠狠操 | 国产一区二区在线播放视频 | 国产一二三区在线观看 | 国产黄视频在线观看 | 国产三级视频在线 | 国产免费午夜 | 麻豆免费精品视频 | 91在线看黄| 日韩一区二区三区视频在线 | 国产剧情一区在线 | 久久久久久久久久久久久影院 | 国产精品18久久久久久首页狼 | 国产中文伊人 | 亚洲人成免费 | 日韩一片| 在线天堂视频 | www国产精品com| 中文字幕在线视频第一页 | 亚洲精品自拍 | 亚欧日韩成人h片 | 91九色国产蝌蚪 | 亚洲永久精品视频 | 久久少妇av | 久久一二三四 | 美国三级黄色大片 | www色综合| 久久久久成人精品亚洲国产 | 最近最新最好看中文视频 | 亚洲 欧美变态 另类 综合 | 成人作爱视频 | 日韩在线激情 | 99久久久久成人国产免费 | 99精品国产免费久久久久久下载 | 欧美日韩一级久久久久久免费看 | 午夜色性片 | 午夜成人免费影院 | 视频一区在线播放 | 亚洲精品永久免费视频 | 日韩草比 | 免费a v观看| 五月天六月婷 | 国产免费资源 | 就要干b | 中文字幕在线网 | 国内外成人在线视频 | www视频在线免费观看 | 婷婷精品 | 久久一区二区三区四区 | 天堂在线一区 | 免费看黄电影 | www五月婷婷 | 久久天堂影院 | 综合精品在线 | 国产香蕉久久 | 欧美午夜激情网 | 人人爽人人爽人人爽学生一级 | 亚洲japanese制服美女 | 久久在线视频精品 | 久99热| 国产精品国产亚洲精品看不卡 | 91精品第一页 | 国产精品久久久久av | 久久九九精品久久 | 97天天干 | 久久爱www.| 亚洲经典视频在线观看 | 色婷婷中文 | 成年人黄色免费网站 | 丁香婷婷深情五月亚洲 | 欧美精品乱码久久久久久按摩 | 婷婷夜夜 | 天天操夜夜爱 | 欧美 亚洲 另类 激情 另类 | 毛片无卡免费无播放器 | 日韩在线观看一区二区 | 天天色.com | 色av婷婷| h动漫中文字幕 | 综合国产视频 | 日韩一区二区三区高清免费看看 | 天天激情综合网 | 一区二区三区www | 日本在线中文 | 九九精品视频在线看 | 综合五月婷婷 | 亚洲性少妇性猛交wwww乱大交 | 国产日韩精品在线观看 | 中日韩欧美精彩视频 | 超碰在线1| 人人插人人草 | 精品久久久久久一区二区里番 | 青春草免费视频 | 亚洲毛片一区二区三区 | 丁香五月亚洲综合在线 | www.天天成人国产电影 | a黄色片 | 色婷婷综合久久久久中文字幕1 | 91精品老司机久久一区啪 | 久久不卡免费视频 | 亚洲精品天天 | 久久五月情影视 | 久草在线免费资源 | 亚洲精品久 | 91视频在线观看下载 | 美女免费视频观看网站 | 国产一区精品在线观看 | 日日干激情五月 | 亚洲精品久久在线 | 欧美日韩大片在线观看 | 91亚洲精品国产 | 最新av中文字幕 | 国产精品免费久久久久 | 久草在线电影网 | 欧洲色综合 | 国产区第一页 | 成在线播放 | 色婷婷免费视频 | 又黄又刺激视频 | 国产码电影 | 四虎成人av | 午夜av大片| 亚洲综合色婷婷 | 在线亚洲天堂网 | 中文字幕人成乱码在线观看 | 麻豆久久精品 | 日韩影视大全 | 国产成人不卡 | 五月综合网 | 国产色婷婷精品综合在线手机播放 | 欧美a级在线播放 | 国产成人av免费在线观看 | 成人在线一区二区三区 | 97人人澡人人添人人爽超碰 | 精品国内| 日韩欧美精品在线视频 | 国产成人精品免费在线观看 | 国产一级淫片免费看 | 精品久久福利 | 三级免费黄色 | 一区二区激情视频 | 国产精品观看视频 | 亚洲理论视频 | 在线国产一区 | 亚洲日本va午夜在线影院 | 久久成人免费电影 | 亚洲午夜久久久久久久久电影网 | 久久亚洲婷婷 | www.激情五月.com | 日韩网站在线观看 | 欧美精品v国产精品v日韩精品 | 成年人免费看av | 99在线热播精品免费99热 | 国产成人精品综合久久久 | 91精品视频观看 | 国产综合激情 | 天天色 天天 | 精品国产视频在线观看 | 久久久久久看片 | 色综合天天色综合 | 久久久久综合 | 中文在线中文a | 成人福利av | www日韩精品 | 美女免费视频一区 | 久操视频在线观看 | 久久精品久久精品久久精品 | 日韩mv欧美mv国产精品 | 久久不卡国产精品一区二区 | 久久久免费国产 | 欧美综合在线观看 | 国产一级二级三级视频 | 黄色在线观看网站 | 91人人爱| 六月丁香婷婷网 | 国产裸体视频网站 | 中文字幕一区二区三区在线观看 | 免费在线播放视频 | 亚洲精品美女久久久久 | 岛国大片免费视频 | 91大神dom调教在线观看 | 精品美女久久久久 | av中文国产 | 欧美日韩精品在线一区二区 | 亚洲精品456在线播放第一页 | 丁香婷婷激情啪啪 | 欧美成年网站 | 中文字幕在线观看免费观看 | 人人看人人| www.黄色小说.com | av超碰在线| 久久免费视频一区 | 欧美精品乱码99久久影院 | 日日躁夜夜躁xxxxaaaa | 亚洲 综合 国产 精品 | 亚洲成人免费 | 午夜视频一区二区三区 | 国产精品99久久久精品免费观看 | 96超碰在线 | 国产成人精品一区二区三区福利 | 久久夜色网 | 91亚洲精品在线 | 中文成人字幕 | 免费a v网站 | 久久不见久久见免费影院 | 97精品国产97久久久久久久久久久久 | 不卡的av | 在线国产一区二区三区 | 黄色小说在线免费观看 | 五月天婷婷丁香花 | 97精品国产97久久久久久春色 | 三上悠亚一区二区在线观看 | 国产自在线观看 | 久久香蕉国产精品麻豆粉嫩av | 国产日韩中文字幕在线 | 欧美做受高潮1 | 视频在线观看91 | 亚洲精品美女在线观看播放 | 中文字幕在线观 | 成人作爱视频 | 中文字幕av在线电影 | 久久精品免费电影 | 国产精品999久久久 久产久精国产品 | 欧美尹人 | 在线三级av | 国产欧美日韩精品一区二区免费 | 综合国产在线观看 | 天天干天天操av | 十八岁免进欧美 | 免费精品久久久 | 天天干夜夜爱 | 麻花豆传媒mv在线观看网站 | 久久国产免费视频 | 久爱精品在线 | 久久精品理论 | 成年人视频在线 | 婷婷在线免费 | 成人影片在线免费观看 | 狠狠操导航| 国产精品久久婷婷六月丁香 | 一区二区三区在线视频111 | www免费| 久热久草在线 | 色综合网在线 | 天天干天天操天天入 | 久久任你操 | 午夜精品久久久久久久99 | 成人高清在线观看 | 在线国产精品一区 | 国产在线视频在线观看 | 四虎永久国产精品 | 亚洲国产精品500在线观看 | 亚洲另类xxxx | 免费成人av在线看 | 高清av免费一区中文字幕 | 99视频精品免费视频 | 亚在线播放中文视频 | 美女视频永久黄网站免费观看国产 | 国产系列 在线观看 | 日韩欧美一区二区在线播放 | 亚洲欧洲精品在线 | av一区二区三区在线播放 | 91在线看| 国产资源在线视频 | 国产在线不卡 | 五月婷婷一级片 | 91精品国产自产在线观看永久 | 精品国产一区二区三区在线 | 婷婷av综合 | 亚洲精品中文字幕视频 | 欧美一区二区三区在线视频观看 | 国产一区二区在线影院 | 日本久久精品 | 亚洲精品色婷婷 | 亚洲视频免费在线 | 免费精品国产va自在自线 | 国产精品 9999 | 亚洲区精品视频 | www.五月天婷婷.com | 91探花国产综合在线精品 | 中文字幕在线免费观看 | 国产精品一区二区在线观看免费 | 国产一区观看 | 久久精品1区| 狠狠色丁香婷婷 | 国产精品美 | 久久精品香蕉视频 | 婷婷午夜| 在线观看免费版高清版 | 日韩免费电影网站 | 一区二区中文字幕在线 | 午夜丁香视频在线观看 | 手机在线中文字幕 | aaa免费毛片 | 天天激情综合 | 最近中文字幕国语免费av | 韩国av免费观看 | 插综合网 | 在线国产一区二区 | 天天干天天摸天天操 | 成人精品视频 | 国产一区二区在线免费视频 | 九九视频免费在线观看 | 三级在线国产 | 超碰在线公开 | 久久99国产精品自在自在app | 国产精品手机播放 | 91大神免费在线观看 | 中文字幕一二三区 | 国产97在线视频 | 国产美女免费观看 | 一区二区三区久久精品 | avhd高清在线谜片 | 天天色婷婷 | 日韩一区二区三区观看 | 精品91视频| 69精品视频在线观看 | 欧美最猛性xxxxx(亚洲精品) | 黄色毛片观看 | 一区二区三区在线观看中文字幕 | 国产原厂视频在线观看 | 国产精品久久久99 | 在线免费观看黄色小说 | 欧洲一区二区三区精品 | av在线播放一区二区三区 | 日本久久久久久久久 | 亚洲精品777 | 精品久久一区 | 日韩在线国产 | 九九九九九精品 | 日韩精品一区在线观看 | 偷拍久久久 | 中国一级片在线播放 | 韩国av在线播放 | 免费十分钟 | 激情综合五月婷婷 | 精品久久久久久亚洲 | 久久国产精品99精国产 | 天天碰天天操 | 国产在线视频导航 | 亚洲在线精品 | 精品国产自在精品国产精野外直播 | 亚洲国产精品传媒在线观看 | 日韩欧美视频免费观看 | 97国产情侣爱久久免费观看 | 91在线视频在线 | 91精品国产欧美一区二区成人 | 精品国自产在线观看 | 视频一区久久 | 婷婷久久婷婷 | 久久涩视频| 国产免费久久av | 久久伊人精品天天 | 国产激情小视频在线观看 | 在线播放 日韩专区 | 伊人成人精品 | 久久成人午夜视频 | 999成人免费视频 | 婷婷中文字幕在线观看 | 成年人视频在线 | 欧美日韩网站 | 麻豆mv在线观看 | 99久久精品国产一区二区成人 | 国产精品黄 | 97超碰在线免费观看 | 精品国产伦一区二区三区观看方式 | 91黄色在线观看 | 欧美亚洲一级片 | 精品久久久久国产免费第一页 | 亚州性色| 国产99在线 | av色网站| 久久精品三级 | 久久精品中文字幕免费mv | 最近中文字幕免费 | 久久不卡国产精品一区二区 | 久久婷婷亚洲 | 久久久久久美女 | 日韩欧美一区二区在线播放 | 精品毛片在线 | 国产一级不卡毛片 | 一区二区三区中文字幕在线 | 日本中文字幕在线看 | 亚洲精品www久久久久久 | 国产一区国产二区在线观看 | 精品久久久久久久久久久久久久久久 | 欧洲精品二区 | 国产中文字幕91 | 97视频人人免费看 | 精品视频免费 | 国产盗摄精品一区二区 | aaa日本高清在线播放免费观看 | 久久精品国产精品亚洲 | 一区二区三区精品在线视频 | 午夜电影久久 | 怡红院av久久久久久久 | 欧美日韩视频在线观看一区二区 | 五月天欧美精品 | 欧美日韩精品在线视频 | 国产福利91精品张津瑜 | 在线成人免费av | 欧美精品久久久久久久 | 国产99久久久国产精品 | 九九视频精品在线 | 亚洲精品www. | 中文字幕国产一区 | 久草视频免费在线观看 | 亚洲涩涩涩 | 在线看av的网址 | av三级在线免费观看 | 美女视频是黄的免费观看 | 91成人国产 | 日韩一区视频在线 | 婷婷5月色| 99成人免费视频 | 一区二区三区四区五区六区 | www.91国产| 婷婷亚洲综合五月天小说 | 欧美午夜剧场 | 精品一二三区 | 91视频免费网址 | 欧美日韩中 | 日韩色视频在线观看 | 8x成人在线| 国产亚洲精品久久久网站好莱 | 999一区二区三区 | 久草视频免费在线播放 | 999精品在线 | 国产精品视频免费观看 | 欧美国产日韩在线观看 | 超碰精品在线 | 又色又爽又激情的59视频 | 国产午夜精品理论片在线 | 91精品视频一区二区三区 | 国产手机精品视频 | 人人看黄色| 久久中国精品 | 99在线视频免费观看 | 国产一区二区精品久久91 | av在线电影免费观看 | 操操综合网 | 久久精品毛片 | 91桃色视频 | 97人人超碰在线 | 中文字幕乱码日本亚洲一区二区 | 西西人体www444 | 播五月综合 | 亚洲综合色视频在线观看 | 人人插人人插 | 国产精品自在欧美一区 | 国产成人久久久77777 | 亚洲国产经典视频 | 中文乱码视频在线观看 | 久久人人做| 一本—道久久a久久精品蜜桃 | 日韩色在线 | 激情五月激情综合网 | 国产一区免费在线 | 国产亚洲精品精品精品 | 在线免费观看视频a | 激情综合婷婷 | 人人干天天射 | av不卡免费看 | 日韩激情视频在线观看 | 日本韩国精品一区二区在线观看 | 久草在线免费资源 | 天天舔天天射天天操 | 久久国产精品一区二区三区 | 欧美黄色软件 | 久久男女视频 | 高清精品视频 | 在线成人一区二区 | 中文字幕精品久久 | 麻豆va一区二区三区久久浪 | 天天爱天天插 | 97狠狠干| 一区二区三区 亚洲 | 久久 一区| 国产呻吟在线 | 一级a性色生活片久久毛片波多野 | 亚洲欧洲国产精品 | 中文字幕影片免费在线观看 | 国产精品电影一区二区 | 国产黄色片久久 | 中文字幕在线免费看线人 | 国产成人精品久久久 | 精品福利在线 | 亚洲区视频在线观看 | 天天操人 | 免费在线观看日韩 | 欧美日韩在线播放一区 | 99热精品国产 | 国产精品毛片一区二区在线 | 日日夜夜人人精品 | 精品免费久久久久久 | 久久午夜电影网 | 日韩av一区二区三区 | 有码视频在线观看 | 狠狠色丁香九九婷婷综合五月 | 亚洲午夜久久久久久久久 | 九色porny真实丨国产18 | 久久久视屏 | 99精品免费观看 | 五月天久久综合 | 国产精品麻豆果冻传媒在线播放 | 深夜免费福利网站 | 一区二区国产精品 | 久久99热久久99精品 | 国产黄色免费看 | 一区二区三区 亚洲 | 韩国在线一区 | 97人人爽| 久热免费在线 | 国产高清视频免费最新在线 | 精品一二三四视频 | 国产精品久久久久免费观看 | 国产特级毛片aaaaaa高清 | 久草综合在线观看 | 亚洲电影黄色 | 超碰97中文| 国产男女无遮挡猛进猛出在线观看 | 日韩大片在线播放 | av免费看av| 日本性久久| 日韩中字在线观看 | 黄色三级免费网址 | 九九在线视频免费观看 | 四虎精品成人免费网站 | 国产在线观看一区 | 国产精品女主播一区二区三区 | 992tv在线成人免费观看 | 99精品一区二区 | 伊人婷婷久久 | 一区免费在线 | 久久午夜国产精品 | 玖玖视频 | 国产手机在线 | 99这里只有精品99 | 国产精品女视频 | 九九热视频在线 | 国产分类视频 | 麻豆国产视频 | 天天干.com | 深爱婷婷激情 | 亚洲少妇自拍 | 九九精品毛片 | 日韩久久精品一区二区三区下载 |