對張子陽先生對委托和事件的兩篇文章的讀後思考(說得很透,內附故事一篇)

来源:http://www.cnblogs.com/JonathanEvents/archive/2016/10/26/6001150.html
-Advertisement-
Play Games

第一篇 C#中的委托和事件 第二篇 C#中的委托和事件(續) 首先,張子陽先生的這是兩篇關於委托和事件間關係的文章,是目前為止我讀過的介紹委托和事件以及非同步調用最簡明清晰文章,作者通過非常有節奏的“標題”->“問題”->“思路”->“實現”->“講解”的結構,分步驟一步一步地將委托和事件的實現、應用 ...


 

第一篇 C#中的委托和事件

第二篇 C#中的委托和事件(續) 

首先,張子陽先生的這是兩篇關於委托和事件間關係的文章,是目前為止我讀過的介紹委托和事件以及非同步調用最簡明清晰文章,作者通過非常有節奏的“標題”->“問題”->“思路”->“實現”->“講解”的結構,分步驟一步一步地將委托和事件的實現、應用與原理闡述得非常清楚,並且在行文期間將自己有趣的思考過程通過生動的語言表達了出來,使人讀起來越發的感興趣,以下就是我讀過這兩篇文章以後,對委托、事件、非同步調用一些新的理解角度的闡述。

 (推薦的張子揚先生的文章鏈接在本文開始處,大家完全可以先不讀我的故事,先去看那兩篇文章,真的非常好玩)        首先要引用作者文中的一個總結語:
委托是一個類,它定義了方法的類型,使得可以將方法當作另一個方法的參數來進行傳遞,這種將方法動態地賦給參數的做法,可以避免在程式中大量使用If-Else(Switch)語句,同時使得程式具有更好的可擴展性。
  我覺得這句話可以從clr-via 設計的理念去闡述我的理解: 委托這個概念存在的作用就是實現了觀察者模式,併在封裝時用類的命名定義了方法的類型,代表了一類參數列表相同的方法。   對,沒錯,就是將各種不同命名的同參數列表的方法,進行了具有可以歸類批量處理能力的封裝,歸類後就可以很方便的把標註了delegate這個關鍵字的具有特定參數列表的方法標記為一個類,併在所有做了訂閱操作(+=)的方法,放置於其編譯後所生成的代理類中的一個List<T>中,那麼在調用的時候,就可以簡單地使用調用delegate的一個實例成員,來通過一次輸入代理所定義的參數列表,調用訂閱了這一委托實例的這一組同類型方法,因為他們需要的參數列表都是相同的嘛~。  

那麼,c#委托到底是怎麼個事兒呢?

  先講個故事,傳說中有這麼一個市(程式域),故事里的主人公就是你(主線程),市裡有100個手工藝人(擁有可以訂閱委托的訂閱函數的類),這100個人里每個人都有用某種指定的材料和工具做出自己最擅長的作品(參數列表相同),這個時候,你發現這些工具和材料都有渠道可以找到,於是,你就想如果把材料變成作品,該有多大市場啊,本著商人逐利的思維,你對外宣佈了這些手工藝人可以找你要材料和工具去製作他自己的作品(初始項目需求)   於是,你就開始想辦法準備搜羅的這些指定材料和工具,這就是在定義委托類型的參數列表,於是你需要為這件事起個業務名,就可以抽象為一種委托類型,隨便起個名字吧就叫delegate SendToolandMaterial(Tools,Material)好了。 你清楚地知道自己要找的工具和材料類型了,並且找好了進貨渠道,所以你可以開始往外公開你可以為需要的人搜集發放材料和工具,大家可以找你來要領取,而你公開消息的這個事兒,就是定義一個屬於你類成員的委托實例(public SendToolandMaterial  sendToolMaterial;)然後,外面得到你的這個消息了(看到公共成員sendToolMaterial),於是開始有人告訴你他要你的工具材料,因為他能做這種材料的作品,這個行為,就是訂閱操作“+=”,實際上就是在編譯運行時,將訂閱函數加入了委托列表。  

委托調用

在你發了一陣工具和材料之後(也有可能一個人都沒發出去呢),這時由於你沒說過什麼時候讓手藝人完成,於是隨便一個知道你發工具和材料這事的人,都可以向你要求看看貨(調用你的委托實例) ,就是要你把之前你發過工具和材料的藝人的作品拿回來給他看看,再決定買不買。於是你看見生意來啦~,就興奮地挨著個兒地找之前找你要過工具和材料的匠人要作品(執行訂閱函數列表)。 由於是同步調用,所以你(主線程)就只能一個一個找人,找到一個就要讓這個收到材料和工具的匠人開始製作,等他做完,再去下一個人那兒收貨,所以你得到所有作品所消耗的時間就是所有匠人做出作品的時間之和,有可能這時人家顧客已經等超時,就走了,有可能你之前發的這幾個匠人做的作品都不符合他要求,但你只發了這幾個人,於是有幾單你耗了時間貨還壓在你手裡,好悲催~不過還是成了幾單賺了些小錢。 這時,你覺得自己的成品不足,不能滿足所有來看貨客人的審美需求,你覺得應該有計劃地去把貨都取來,然後再開始張羅客人看貨,這樣可以賣出最多的作品,於是你就開始盤算了……   

c#事件Event與委托delegate的關係

故事繼續,還是這個能發工具和材料的你,還是這個市,經歷了上面挨個收作品的這個事,你覺得隨便一個認識你的人都可以過來要求你中斷你自己的事去要作品(執行委托)這一點非常不爽(其實挨個收作品很耗時間,這也讓顧客很不滿意,但你並沒有意識到這也急需改進),所以,你決定不讓外人有權這樣要求你,於是你就對外邊說了,雖然我發放了工具和原料,但是我只在我公開展示的時候,大家才能來進行參觀交易(事件對委托的內部封裝)。由於是內部決定的執行計劃,別人說什麼時候要參觀就不管用了,這樣,你就把之前發工具材料的那個委托(delegate)封裝成了一個事件(event),發放工具變得隨時可以發放(對外定義是public event),但什麼時候去收作品這個事兒就變成你自己說了算了(編譯時會變成private),看你心情了,也許你覺得發50個就可以收一圈,也許原材料不足,只能發30人份就得收一圈,這取決於你想在哪個結點取執行這個委托列表,所以你每次都能把匠人或原料利用完全。   所以,事件的原理其實就是委托,在編程的時候也完全能用委托去實現訂閱和批量調用,只不過事件將委托封裝成了內部的調用特性(至於事件怎麼調用怎麼定義,以及編譯後變成什麼代碼,可以去那兩篇美文里扣,我這兒只講故事~)   由於應用了內部事件,沒有人打擾你分發任務了,於是慢慢你就覺得,這麼乾還真是特麽夠慢啊……,100個人我挨著個要,這不傻一漏麽?而且,別人中途找我要東西,我也顧不上理他啊,我(主線程)還在外面挨著個收東西呢,這不氣跑了客人才怪。不行,我得換個套路做買賣。  

遇到問題之後,你開始了思考,於是,非同步執行的概念誕生了

前思後想,你覺得發完了以後,告訴他們(MyEvent.GetInvocationList())一塊兒開始工作(beginInvoke(toolobj , meterailobj , null, null)),弄完我再收作品(IAsyncResult )不得了麽?就算我不把工具和材料全發完了,誰領了東西誰就開始,我給他個快遞電話,弄完給我遞過來不得了?(於是你養活了這裡的快遞行業)?這時候反正他開始了,誰來找我要我就專門等他那個幹完給我(IAsyncResult asyncResult = del.BeginInvoke(2,5,null,null); 這樣我就能在他們幹活的時候繼續乾我自己的事了(主線程任務),就算中間我想做交易,我就去催特定的人給我他的作品(EndInvoke(asyncResult),然後再乾我別的事兒也行啊,這時候別人也沒停止工作(線程池(Thread.CurrentThread.IsThreadPoolThread)),這效率多高!   於是你開始,採用這個新的商業策略,你把做生意的理念改了,一有材料往外發,作品都由匠人領了就開始創作,要麼就在是收快遞,要麼就是在見客戶做交易,效率高了,聲意也越來越紅火,忙得好生了得啊!  

非同步的回調以及非同步調用傳入數據

故事繼續。幹了好一陣生意,你發現你自己已經熟知了市場行情,也對藝術有了一定的鑒賞力,於是你就琢磨著怎樣讓這幫匠人拿回材料工具後,能按照自己的意思去弄出作品,於是你開始琢磨著每次派發工具和材料的同時再給匠人一些主題之類的信息,這樣就充分利用了手頭的工匠資源,能更讓出活的作品符合當前市場的預期。   於是你就這麼幹了,每次發了工具在手藝人表示可以開始乾((beginInvoke(null, EventArgs.Empty, null, null) )的時候,你就來勁了,大吹一通你現在的靈感,多麼多麼希望達到一種效果這才是藝術之類的牛,然後你就讓匠人深受感染,根據你的思想感情(string data = "Any data you want to pass.";)去創作作品。由於是按照你的意思來的,所以在做完之後,你將保有修改作品的權利 (AsyncCallback callBack = new AsyncCallback(OnAddComplete);),併為此塞給了一筆額外的錢(參數處理的時間開銷)給匠人。於是匠人原來的創作模式變了,硬生生塞入了你的意思以後,變成了出品後你還能修改的作品(del.BeginInvoke(toolobj,meterailobj , callBack, data);)   獲得了高度的CPU線程併發效率和自由修改結果的權利之後,你對這種新的工作模式相當得意,並樂此不疲得開始將所有的想法付諸於作品的產生,瘋狂地對原有合作的匠人們輸入個性化的意見(超級多樣化的傳入參數),並且經常批評不能處理好你的意見的工匠,認為他們做出來的作品不行,在得到作品後大量進行修改(為匹配需求寫了很多的衍生回調函數)……  

非同步的好處

我認為非同步最大的好處,就是主線程可以像故事里做生意的主人公抓人同時做事那樣,抓出線程池中可用的資源及時執行(最頂上那兩篇文章裡面已經詳細解釋過是怎樣的一個情景了,而且寫得非常易懂,我就不畫蛇添足解釋了),然後執行的過程、結果以及對結果的控制,都通過beginInvoke 返回的 IAsyncResult,傳入參數AsyncCallback 以及傳入的數據參數,進行了很好的封裝,可以使單線等待任務變為併發線程任務,很好得封裝了一組線程協作的實現。  

最後我為故事編了個皆大歡喜的結尾:

很長一段時間,匠人們跟著你的意思做事,並且做出來的東西被你根據自己的審美進行了許多修改,你愈發沉迷於高效率與自我實現的快感中,由於每次都需要額外付一大筆錢給匠人,而且越難的主題越貴,導致了開銷大幅增長(傳入參數類型多變產生的訂閱參數修改開銷以及額外的業務回調開銷),再由於對手都是各種胡吹各種挖牆腳的競爭(更多的同種類非同步調用),市場變化很快,並且由於你有了錢了就學壞,出入燈紅酒綠的場所,口無遮攔得吹噓自己業務的處理能力以及自己的藝術鑒賞力(認為伺服器性能夠用而開始盲目擴展業務,導致單節點性能瓶頸),名聲就漸漸變差,有錢人買你的東西覺得有點掉價,於是買的人也少了,投入小於產出,很快你自己的產業就敗落了(服務能力下降,導致服務廢棄),由擁有更好名聲更好經營習慣合作無間的商人群體取代了(謹慎擴展業務,不斷完善架構最終催生出了分散式服務架構),真是皆大歡喜啊~。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、MSMQ是什麼 Message Queuing(MSMQ) 是微軟開發的消息中間件,可應用於程式內部或程式之間的非同步通信。主要的機制是:消息的發送者把自己想要發送的信息放入一個容器中(我們稱之為Message),然後把它保存至一個系統公用空間的消息隊列(Message Queue)中;本地或者是 ...
  • /* * (un)comment correct payload first (x86 or x64)! * * $ gcc cowroot.c -o cowroot -pthread * $ ./cowroot * DirtyCow root privilege escalation * Back ...
  • 版權聲明:本文發佈於http://www.cnblogs.com/yumiko/,版權由Yumiko_sunny所有,歡迎轉載。轉載時,請在文章明顯位置註明原文鏈接。若在未經作者同意的情況下,將本文內容用於商業用途,將保留追究其法律責任的權利。如果有問題,請以郵箱方式聯繫作者(793113046@q ...
  • 在使用系統時,我們或多或少的有一些搜索、查找的需求,必須要在文本中搜索某個關鍵字,或者過濾出文本中某些特定的行。grep 命令就為我們提供了這樣一個功能,同時,grep 還可以使用正則表達式進行匹配,這是一個強大的功能,有必要好好掌握。 1.grep 初體驗 grep PATTERN [OPTION ...
  • LAMP環境配置安裝註意安裝步驟及說明事項。 LAMP安裝各種問題解決 1. 訪問ftp報錯 解決: 關閉selinux vi /etc/selinux/config 內容修改為: selinux=disable 之後重啟reboot。 下圖分別為selinux關閉前 和 關閉後: 2. 依賴軟體查... ...
  • 通常在 Shell 中執行命令的時候,我們會在輸入命令的下方看到執行結果,操作系統預設將命令的執行結果輸出到顯示器上。當然,我們也可以手動的指定輸出路徑,或者輸入路徑,這就是 I/O 重定向。 1.標準輸出重定向 使用 cat 命令,命令的執行結果將會列印在屏幕中。 我們使用 > 來進行輸出重定向, ...
  • 1.值類型: 1 static void Main(string[] args) 2 { 3 int a = 5; 4 int b = 3; 5 NumVal(a, b); 6 Console.WriteLine("a={0},b={1}", a, b); //輸出結果為:a=5,b=3 7 8 C ...
  • 由於項目需要在首頁搞一個訂單數量的走勢圖,經過多方查找,體驗,感覺ECharts不錯,封裝的很細,我們只需要看自己需要那種類型的圖表,搞定好自己的json數據就OK。至於說如何體現出來,官網的教程很詳細。大家可以去看下。大概瞭解下用法就OK。 百度ECharts 3:http://echarts.b ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...