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

本來應該學習泛型與委托的,但是發現C#這里還沒有系統的記錄過委托與事件,所以先打算把委托與事件補上再繼續泛型與委托的記錄。
然后呢,今天如果沒有意外的話unity方面也會記錄一些關于編輯器擴展的筆記,還有一直想學習的C#socket(套接字)的筆記。
萬事開頭難,只要開了頭,剩下的事就可以繼續下去了。
關于委托與事件,前面其實也有記錄到,但是那是關于在unity中使用委托與事件的一個小事例而已,這里主要是記錄一下C#中關于委托與事件到底是講的什么?如何使用?以及有什么坑需要注意。
我打算把這個寫成一個系列,畢竟我也是邊學邊寫,然后呢,后續也會再次寫到如何將委托與事件運用到unity中。
還有就是,還會重新再學一下C#的設計模式,基礎一定要打牢固。

OK,廢話說完,開始進入正題:
首先什么是委托?委托,delegate,是表示對具有特定參數列表和返回類型的方法的引用的類型。 在實例化委托時,你可以將其實例與任何具有兼容簽名和返回類型的方法相關聯。 你可以通過委托實例調用方法。(MSDN解釋)
MSDN給出的解釋說實話,很惡心,還繞口。
其實,在我看來,委托就是一種自定義的類型,就類似于一個class,然后我們可以通過這個類型來創建實例對象,這個實例對象,其實類似于引用類型的對象那樣,存儲的是一個“地址”,只不過這個地址指向的是函數方法,也就是說,委托實例就類似于C++中的函數指針那樣。
委托是安全封裝方法的類型,類似于C和C++中的函數指針,委托是面向對象的。類型安全的和可靠的。
總結: 委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞。
可能解釋的還是很亂,不過沒關系,有個了解,不需要死扣定義。

繼續,來看一下委托的定義:public delegate void MyDelegate(string str);
注意,從這兒定義來看,其實委托的定義與一般方法的定義,只是多了一個delegate關鍵字而已。
解釋一下整個定義的意思:
public就是訪問權限,沒有什么差別。
delegate 聲明委托的關鍵字。
void,方法的返回值,如果你將某個方法綁定到委托上,那么該方法的返回值要與委托定義時的一致,在這里了都要是void。
MyDelegate,委托的名字,其實就是一個類名,我們可以使用它來創建我們的委托對象。(string str),方法參數,如果你將某個方法綁定到委托上,那么該方法的參數要與委托定義時的一致,在這里參數是一個string類型。
當我們聲明一個委托后,在編譯時,會自動生成一個委托類型,自動繼承MulticastDelegate,而MulticastDelegate又是繼承自Delegate類的。
注意:這里,我們聲明的是一個委托,雖然看起來像是聲明了一個方法,它沒有具體的實現,因為它相當于一個類。

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

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);
    }
 }

}

結果會是什么?輸出:
圖片
圖片

OK,用這個例子來解釋一下,如何使用委托:
首先在Main()函數中,我們創建了一個委托對象 myDel,以及一個TestMethod類的對象 testMethod,
然后我們將testMethod的一個實例方法 InstanrMethod用“=”“賦值”給了myDel,有沒有很熟悉的樣子?
其實類似于,int i;i=1;這個樣子的賦值,委托就是方法的引用類型,其對象的值就是一個方法名。前提是,該方法與委托的定義一致。
然后又有兩個運算符,“+=”和“-=”,委托允許向其注冊方法,那么也就意味著,可以注銷方法,這就是observe模式的基礎。

對于委托可以有多個方法,我們稱之為多播。

而且從這個例子可以看出:使用委托對象可以封裝實例方法和靜態方法。

其實,在定義委托的時候,我們還能這樣,如下圖:
圖片

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

這是會報錯的,如下圖:

2.png

是不是會想到構造函數,這個問題的解決方式,我是采用了,將委托的定義在封裝一次,如下所示:

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);
        }
    }
}

怎么說呢,就類似于一種曲線救國的樣子,既然我不能new出來你,那么我就new出來封裝你的類。然后用這個類的對象來調用你,大概就是這個意思。
甚至,我們可以對委托進行“加減運算”以及判斷是否相等的邏輯判斷(PS:其實就是增加方法與刪除方法)
比如,我們來改一下Main函數里的代碼:

3.png

我們來看看結果:

5.png

看到了沒有,可以進行邏輯判斷,當然,你可以自己去嘗試一下減法的作用。

OK,關于委托的最最基礎的知識點先整理到這里,還有一些關于匿名方法和Lambda表達式運用在委托中,會在下篇中記錄。

那么現在開始記錄一下關于事件的基礎知識:
什么是事件呢?
老規矩,來看一下MSDN上的解釋:
類或對象可以通過事件向其他類或對象通知發生的相關事情,發送事件的類稱為“發行者”,接收事件的類稱為“訂戶”。
解釋的還算是清晰吧,不過可能對于一些新人來說還是一頭霧水的樣子。

那么開始事件的記錄:我先說一句:事件是對委托的隱藏。(老規矩,不要試圖去理解它,有個印象就可以了).
先來說一下,為什么需要事件?
面向對象三大特性:繼承,封裝,多態。其中封裝就是指將某些我們不想讓外部看到的東西包圍起來,給外部留出來一個接口,可以使用就行,不讓外部的人員對其進行改動,這是做使得代碼更加的安全。
我們現在都知道了,委托其實就是一個類,那么對于其對象而言,訪問權限肯定是該public的時候public,該private的時候private。
但是,當private的時候,我們就在客戶端無法調用它了,也就是說它就沒什么卵用了,那我們干嘛還聲明它出來。
但是,當public的時候,又嚴重的破壞了封裝性,我們可以隨意的修改,這點后果也很嚴重。
如果是針對別的類型,比如string,int等等,那么我們可能就會想到用屬性來對其進行封裝。
于是,Event出場了,它封裝了委托類型的變量,使得:在類的內部,不管你聲明它是public還是protected,它總是private的。在類的外部,注冊“+=”和注銷“-=”的訪問限定符與你在聲明事件時使用的訪問符相同。
OK,來看一下事件的定義:我們將委托去事件放到同一個類中,并且給一個觸發方法:

    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;
這個事件的定義,其實就是比創建委托對象多了一個關鍵字event。
然后在Main函數中,我們這樣寫:

           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();

這個時候,你再去用“=”就沒有卵用了。
先看一下運行結果:

10.png

當觸發事件的方法發生的時候,訂閱該事件的方法都會按照訂閱順序進行執行動作。
其實,這已經算是一個很簡版很簡版的observe模式的例子了。
還有就是,有時候我們會遇到帶有EventArgs參數的事件模型,這個是干什么用的呢?
其實這個是.Net Framework中的委托與事件,其有一個編碼規范。
我們先看一下編碼規范,下一篇再講如何編寫這樣的委托與事件。
編碼規則:

  • 委托類型的名稱都應該以EventHandler結束。
  • 委托的原型定義:有一個void返回值,并接受兩個輸入參數:一個Object 類型(就是監視對象),一個 EventArgs類型(或繼承自EventArgs)(其存儲了觀察者感興趣的數據,也就是事件觸發的關鍵點)。
  • 事件的命名為 委托去掉 EventHandler之后剩余的部分。
  • 繼承自EventArgs的類型應該以EventArgs結尾。

系列一就先記錄到這里。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,818評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,733評論 18 399
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,711評論 25 708
  • 建議掛載的幾大目錄: /-------根目錄,唯一必須掛載的目錄。不要有任何的猶豫,選一個分區,掛載它!(在絕大多...
    我的女友漏氣了閱讀 554評論 0 0
  • 小時候,對虛幻的言情小說沒有任何的興趣,所以,我對幻城知之甚少,對小王子櫻空釋的了解僅限于一個名字而已。 記得當時...
    青色花蕾閱讀 3,019評論 0 2