C#——委托與事件系列一

本來應(yīng)該學(xué)習(xí)泛型與委托的巩步,但是發(fā)現(xiàn)C#這里還沒有系統(tǒng)的記錄過委托與事件旁赊,所以先打算把委托與事件補(bǔ)上再繼續(xù)泛型與委托的記錄。
然后呢竟闪,今天如果沒有意外的話unity方面也會(huì)記錄一些關(guān)于編輯器擴(kuò)展的筆記离福,還有一直想學(xué)習(xí)的C#socket(套接字)的筆記。
萬事開頭難瘫怜,只要開了頭术徊,剩下的事就可以繼續(xù)下去了。
關(guān)于委托與事件鲸湃,前面其實(shí)也有記錄到赠涮,但是那是關(guān)于在unity中使用委托與事件的一個(gè)小事例而已,這里主要是記錄一下C#中關(guān)于委托與事件到底是講的什么暗挑?如何使用笋除?以及有什么坑需要注意。
我打算把這個(gè)寫成一個(gè)系列炸裆,畢竟我也是邊學(xué)邊寫垃它,然后呢,后續(xù)也會(huì)再次寫到如何將委托與事件運(yùn)用到unity中烹看。
還有就是国拇,還會(huì)重新再學(xué)一下C#的設(shè)計(jì)模式,基礎(chǔ)一定要打牢固惯殊。

OK酱吝,廢話說完,開始進(jìn)入正題:
首先什么是委托土思?委托务热,delegate,是表示對(duì)具有特定參數(shù)列表和返回類型的方法的引用的類型己儒。 在實(shí)例化委托時(shí)崎岂,你可以將其實(shí)例與任何具有兼容簽名和返回類型的方法相關(guān)聯(lián)。 你可以通過委托實(shí)例調(diào)用方法闪湾。(MSDN解釋)
MSDN給出的解釋說實(shí)話冲甘,很惡心,還繞口。
其實(shí)损合,在我看來省艳,委托就是一種自定義的類型,就類似于一個(gè)class嫁审,然后我們可以通過這個(gè)類型來創(chuàng)建實(shí)例對(duì)象,這個(gè)實(shí)例對(duì)象赖晶,其實(shí)類似于引用類型的對(duì)象那樣律适,存儲(chǔ)的是一個(gè)“地址”,只不過這個(gè)地址指向的是函數(shù)方法遏插,也就是說捂贿,委托實(shí)例就類似于C++中的函數(shù)指針那樣。
委托是安全封裝方法的類型胳嘲,類似于C和C++中的函數(shù)指針厂僧,委托是面向?qū)ο蟮摹n愋桶踩暮涂煽康摹?br> 總結(jié): 委托是一個(gè)類了牛,它定義了方法的類型颜屠,使得可以將方法當(dāng)作另一個(gè)方法的參數(shù)來進(jìn)行傳遞。
可能解釋的還是很亂鹰祸,不過沒關(guān)系甫窟,有個(gè)了解,不需要死扣定義蛙婴。

繼續(xù)粗井,來看一下委托的定義:public delegate void MyDelegate(string str);
注意,從這兒定義來看街图,其實(shí)委托的定義與一般方法的定義浇衬,只是多了一個(gè)delegate關(guān)鍵字而已。
解釋一下整個(gè)定義的意思:
public就是訪問權(quán)限餐济,沒有什么差別耘擂。
delegate 聲明委托的關(guān)鍵字。
void颤介,方法的返回值梳星,如果你將某個(gè)方法綁定到委托上,那么該方法的返回值要與委托定義時(shí)的一致滚朵,在這里了都要是void冤灾。
MyDelegate,委托的名字辕近,其實(shí)就是一個(gè)類名韵吨,我們可以使用它來創(chuàng)建我們的委托對(duì)象。(string str)移宅,方法參數(shù)归粉,如果你將某個(gè)方法綁定到委托上椿疗,那么該方法的參數(shù)要與委托定義時(shí)的一致,在這里參數(shù)是一個(gè)string類型糠悼。
當(dāng)我們聲明一個(gè)委托后届榄,在編譯時(shí),會(huì)自動(dòng)生成一個(gè)委托類型倔喂,自動(dòng)繼承MulticastDelegate铝条,而MulticastDelegate又是繼承自Delegate類的。
注意:這里席噩,我們聲明的是一個(gè)委托班缰,雖然看起來像是聲明了一個(gè)方法,它沒有具體的實(shí)現(xiàn)悼枢,因?yàn)樗喈?dāng)于一個(gè)類埠忘。

再次繼續(xù),如何使用委托馒索?(先不要著急事件)
直接來看例子好了:
首先我在一個(gè)類中寫了兩個(gè)方法莹妒,一個(gè)實(shí)例方法,一個(gè)靜態(tài)方法:
public class TestMethod{
public static void StaticMethod(string str)
{
Console.WriteLine("StaticMethod:"+str);
}
public void InstantMethod(String str)
{
Console.WriteLine("InstantMethod:"+str);
} }
然后在program類中使用這個(gè)類:

class Program
 {
     static void Main(string[] args){
         MyDelegate myDel;
         TestMethod testMethod = new TestMethod();
         myDel=testMethod.InstantMethod;
         myDel+=TestMethod.StaticMethod;
         myDel("AAA");
         myDel-=testMethod.InstantMethod;
         myDel("BBB");
     }
 public delegate void MyDelegate(string str);
 
 public class TestMethod
 {
    public static void StaticMethod(string str)
    {
        Console.WriteLine("StaticMethod:"+str);
    }

    public void InstantMethod(String str)
    {
          Console.WriteLine("InstantMethod:"+str);
    }
 }

}

結(jié)果會(huì)是什么双揪?輸出:
圖片
圖片

OK动羽,用這個(gè)例子來解釋一下,如何使用委托:
首先在Main()函數(shù)中渔期,我們創(chuàng)建了一個(gè)委托對(duì)象 myDel运吓,以及一個(gè)TestMethod類的對(duì)象 testMethod,
然后我們將testMethod的一個(gè)實(shí)例方法 InstanrMethod用“=”“賦值”給了myDel疯趟,有沒有很熟悉的樣子拘哨?
其實(shí)類似于,int i;i=1;這個(gè)樣子的賦值信峻,委托就是方法的引用類型倦青,其對(duì)象的值就是一個(gè)方法名。前提是盹舞,該方法與委托的定義一致产镐。
然后又有兩個(gè)運(yùn)算符,“+=”和“-=”踢步,委托允許向其注冊(cè)方法癣亚,那么也就意味著,可以注銷方法获印,這就是observe模式的基礎(chǔ)述雾。

對(duì)于委托可以有多個(gè)方法,我們稱之為多播。

而且從這個(gè)例子可以看出:使用委托對(duì)象可以封裝實(shí)例方法和靜態(tài)方法玻孟。

其實(shí)唆缴,在定義委托的時(shí)候,我們還能這樣黍翎,如下圖:
圖片

但是面徽,注意,如果我們直接:MyDelegate myDel = new MyDelegate()匣掸;

這是會(huì)報(bào)錯(cuò)的斗忌,如下圖:

2.png

是不是會(huì)想到構(gòu)造函數(shù),這個(gè)問題的解決方式旺聚,我是采用了,將委托的定義在封裝一次眶蕉,如下所示:

namespace class1
{
    class Program
    {
        static void Main(string[] args)
        {
            Method mt = new Method();
            Del del = new Del();
            del.myDel = mt.InstantMethod;
            del.myDel += Method.StaticMethod;
            Console.ReadKey();
        }
    }
    class Del
    {
        public MyDelegate myDel;

    }
    public delegate void MyDelegate(string str);

    class Method
    {
        public void InstantMethod(string str)
        {
            Console.WriteLine("InstantMethod" + str);
        }
        public static void StaticMethod(string str)
        {
            Console.WriteLine("StaticMethod" + str);
        }
    }
}

怎么說呢砰粹,就類似于一種曲線救國(guó)的樣子,既然我不能new出來你造挽,那么我就new出來封裝你的類碱璃。然后用這個(gè)類的對(duì)象來調(diào)用你,大概就是這個(gè)意思饭入。
甚至嵌器,我們可以對(duì)委托進(jìn)行“加減運(yùn)算”以及判斷是否相等的邏輯判斷(PS:其實(shí)就是增加方法與刪除方法)
比如,我們來改一下Main函數(shù)里的代碼:

3.png

我們來看看結(jié)果:

5.png

看到了沒有谐丢,可以進(jìn)行邏輯判斷爽航,當(dāng)然,你可以自己去嘗試一下減法的作用乾忱。

OK讥珍,關(guān)于委托的最最基礎(chǔ)的知識(shí)點(diǎn)先整理到這里,還有一些關(guān)于匿名方法和Lambda表達(dá)式運(yùn)用在委托中窄瘟,會(huì)在下篇中記錄衷佃。

那么現(xiàn)在開始記錄一下關(guān)于事件的基礎(chǔ)知識(shí):
什么是事件呢?
老規(guī)矩蹄葱,來看一下MSDN上的解釋:
類或?qū)ο罂梢酝ㄟ^事件向其他類或?qū)ο笸ㄖl(fā)生的相關(guān)事情氏义,發(fā)送事件的類稱為“發(fā)行者”,接收事件的類稱為“訂戶”图云。
解釋的還算是清晰吧惯悠,不過可能對(duì)于一些新人來說還是一頭霧水的樣子。

那么開始事件的記錄:我先說一句:事件是對(duì)委托的隱藏琼稻。(老規(guī)矩吮螺,不要試圖去理解它,有個(gè)印象就可以了).
先來說一下,為什么需要事件鸠补?
面向?qū)ο笕筇匦裕豪^承萝风,封裝,多態(tài)紫岩。其中封裝就是指將某些我們不想讓外部看到的東西包圍起來规惰,給外部留出來一個(gè)接口,可以使用就行泉蝌,不讓外部的人員對(duì)其進(jìn)行改動(dòng)歇万,這是做使得代碼更加的安全。
我們現(xiàn)在都知道了勋陪,委托其實(shí)就是一個(gè)類贪磺,那么對(duì)于其對(duì)象而言,訪問權(quán)限肯定是該public的時(shí)候public诅愚,該private的時(shí)候private寒锚。
但是,當(dāng)private的時(shí)候违孝,我們就在客戶端無法調(diào)用它了刹前,也就是說它就沒什么卵用了,那我們干嘛還聲明它出來雌桑。
但是喇喉,當(dāng)public的時(shí)候,又嚴(yán)重的破壞了封裝性校坑,我們可以隨意的修改拣技,這點(diǎn)后果也很嚴(yán)重。
如果是針對(duì)別的類型撒踪,比如string过咬,int等等,那么我們可能就會(huì)想到用屬性來對(duì)其進(jìn)行封裝制妄。
于是掸绞,Event出場(chǎng)了,它封裝了委托類型的變量耕捞,使得:在類的內(nèi)部衔掸,不管你聲明它是public還是protected,它總是private的俺抽。在類的外部敞映,注冊(cè)“+=”和注銷“-=”的訪問限定符與你在聲明事件時(shí)使用的訪問符相同。
OK磷斧,來看一下事件的定義:我們將委托去事件放到同一個(gè)類中振愿,并且給一個(gè)觸發(fā)方法:

    class EventTest
    {
        public delegate void MethodHandler(string str);
        public event MethodHandler MethodEvent;
        
        public void Print(string str)
        {
            if (MethodEvent != null)
            {
                MethodEvent(str);
            }
        }
    }

看到了沒有捷犹,public event MethodHandler MethodEvent;
這個(gè)事件的定義,其實(shí)就是比創(chuàng)建委托對(duì)象多了一個(gè)關(guān)鍵字event冕末。
然后在Main函數(shù)中萍歉,我們這樣寫:

           EventTest ev = new EventTest();
            Method mt = new Method();
            ev.MethodEvent += mt.method;
            ev.MethodEvent += mt.InstantMethod;
            ev.MethodEvent += Method.StaticMethod;
            ev.Print("ppppppppppppppppp");
            Console.ReadKey();

這個(gè)時(shí)候,你再去用“=”就沒有卵用了档桃。
先看一下運(yùn)行結(jié)果:

10.png

當(dāng)觸發(fā)事件的方法發(fā)生的時(shí)候枪孩,訂閱該事件的方法都會(huì)按照訂閱順序進(jìn)行執(zhí)行動(dòng)作。
其實(shí)藻肄,這已經(jīng)算是一個(gè)很簡(jiǎn)版很簡(jiǎn)版的observe模式的例子了蔑舞。
還有就是,有時(shí)候我們會(huì)遇到帶有EventArgs參數(shù)的事件模型嘹屯,這個(gè)是干什么用的呢攻询?
其實(shí)這個(gè)是.Net Framework中的委托與事件,其有一個(gè)編碼規(guī)范州弟。
我們先看一下編碼規(guī)范蜕窿,下一篇再講如何編寫這樣的委托與事件。
編碼規(guī)則:

  • 委托類型的名稱都應(yīng)該以EventHandler結(jié)束呆馁。
  • 委托的原型定義:有一個(gè)void返回值,并接受兩個(gè)輸入?yún)?shù):一個(gè)Object 類型(就是監(jiān)視對(duì)象)毁兆,一個(gè) EventArgs類型(或繼承自EventArgs)(其存儲(chǔ)了觀察者感興趣的數(shù)據(jù)浙滤,也就是事件觸發(fā)的關(guān)鍵點(diǎn))。
  • 事件的命名為 委托去掉 EventHandler之后剩余的部分气堕。
  • 繼承自EventArgs的類型應(yīng)該以EventArgs結(jié)尾纺腊。

系列一就先記錄到這里。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末茎芭,一起剝皮案震驚了整個(gè)濱河市揖膜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梅桩,老刑警劉巖壹粟,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宿百,居然都是意外死亡趁仙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門垦页,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雀费,“玉大人,你說我怎么就攤上這事痊焊≌蛋溃” “怎么了忿峻?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)辕羽。 經(jīng)常有香客問我逛尚,道長(zhǎng),這世上最難降的妖魔是什么逛漫? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任黑低,我火速辦了婚禮,結(jié)果婚禮上酌毡,老公的妹妹穿的比我還像新娘克握。我一直安慰自己,他們只是感情好枷踏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布菩暗。 她就那樣靜靜地躺著,像睡著了一般旭蠕。 火紅的嫁衣襯著肌膚如雪停团。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天掏熬,我揣著相機(jī)與錄音佑稠,去河邊找鬼。 笑死旗芬,一個(gè)胖子當(dāng)著我的面吹牛舌胶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播疮丛,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼幔嫂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了誊薄?” 一聲冷哼從身側(cè)響起履恩,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呢蔫,沒想到半個(gè)月后切心,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡片吊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年昙衅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片定鸟。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡而涉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出联予,到底是詐尸還是另有隱情啼县,我是刑警寧澤材原,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站季眷,受9級(jí)特大地震影響余蟹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜子刮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一威酒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挺峡,春花似錦葵孤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至狭姨,卻和暖如春宰啦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背饼拍。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工赡模, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人师抄。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓纺裁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親司澎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理栋豫,服務(wù)發(fā)現(xiàn)挤安,斷路器,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法丧鸯,類相關(guān)的語法蛤铜,內(nèi)部類的語法,繼承相關(guān)的語法丛肢,異常的語法围肥,線程的語...
    子非魚_t_閱讀 31,623評(píng)論 18 399
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,077評(píng)論 25 707
  • 建議掛載的幾大目錄: /-------根目錄,唯一必須掛載的目錄蜂怎。不要有任何的猶豫穆刻,選一個(gè)分區(qū),掛載它8懿健(在絕大多...
    我的女友漏氣了閱讀 545評(píng)論 0 0
  • 小時(shí)候氢伟,對(duì)虛幻的言情小說沒有任何的興趣榜轿,所以,我對(duì)幻城知之甚少朵锣,對(duì)小王子櫻空釋的了解僅限于一個(gè)名字而已谬盐。 記得當(dāng)時(shí)...
    青色花蕾閱讀 2,978評(píng)論 0 2