讓他代我做:Delegate 從使用到設計,為目的而進化
在人生的旅途中,有些行動,不是為了此刻,而是為了將來某個尚未到來的時刻,悄悄種下伏筆。
就像在一場重要的典禮上,你輕聲叮囑朋友:「等我上台尻校長的光頭時,幫我拍一張照片。」你清楚地設定了做什麼,但並沒有干涉朋友用哪台相機、站在哪個角度,只是信任對方,讓他自由捕捉那個瞬間。
又像叫了一份外送,你指定了:「請把三商巧福送到我家門口。」你決定了目標,但至於外送員選擇騎機車、開車,走哪條路線抵達,則完全交給他靈活安排。
你無需親手掌控每一個細節,只需種下清楚的意圖,並信任交付
這種「指定意圖,委託執行」的方式,在程式設計的世界裡的 Delegate
在上一篇中,我們認識了 Delegate 的基本結構與意義;而這一篇,我們將走得更深,去感受它在現實設計中如何展現靈活的力量,又如何結合泛型,成為更強大而多變的工具;更會看見它化身為 Action、Func、Predicate,滲透進每一段程式邏輯之中。
從重複中提煉靈活:泛型的智慧設計在開發過程中,我們遇過這種情況:
12345public delegate int ...
讓他代我做:Delegate 應用實踐
在 第一篇
我們從「什麼是委派(Delegate)」開始,理解它的誕生是為了解決什麼樣的需求:將行為作為參數傳遞。
接著第二篇
我們進一步探討了實務上會遇到的挑戰,以及 .NET 框架提供的標準解法(像是泛型委派 Action、Func、Predicate)。
這次,我們要來真正動手,體會 Delegate 如何在日常開發中,帶來更高的彈性與更好的設計感。
🏪 動態選擇條件總結訂單資訊💬說明
你有一組訂單資料 Order,客戶希望可以動態選擇條件,例如:
只加總金額超過 500 的訂單
只加總客戶名稱是 “Allen” 的訂單
加總指定客戶清單裡的人(比如 VIP 客戶)
請設計一個方法,讓使用者自訂篩選條件(以委派的方式傳入),然後針對符合條件的訂單做加總。
解析
先定義甚麼是 Order
123456789101112public class Order{ public int Id { get; set; } public string OrderId { get; set; } public string Cust ...
讓他代我說:Delegate 的溫柔設計學
在人生裡,我們總在不知不覺中進行著「委派」。不是公司開會那種,而是日常裡那些再自然不過的小任務外包。
👦:「阿嬤,我要出門了,幫我跟媽媽說我會晚點回家~」你沒直接說,而是把「傳話」這件事交給了阿嬤。這一刻,你不是孫子,你是個指派 callback 的主控者。
而在程式世界裡,這樣的行為就叫作:delegate ——拜託別人幫你做某事,但怎麼做、什麼時候做,全憑對方自由發揮。
123456789101112131415161718//// 定義要執行的任務的事件樣貌delegate void PassMessage(string message);public class You{ public void AskSomeoneToPassMessage(PassMessage messenger) { messenger("我會晚一點回家"); }}//// 執行者自己決定怎麼執行void GrandmaPassMessage(string msg){ Console.Writ ...
Deep Clone
鏡中的自己Shallow Copy & Deep Copy透過序列化進行 Deep CopyAutomapper 進行 Deep Copysummary還記得小時候,我總覺得「鏡中的自己」很神奇。他會跟著我一起笑、一起生氣、一起模仿我的每個動作。但漸漸長大才明白——那並不是真正的「另一個我」,而只是一個淺薄的影子。
程式世界裡,物件的複製也是這樣。有時候,我們只是得到了「鏡子裡的自己」(Shallow Copy),稍不注意,動到這邊,另一邊也跟著被牽連。而有時候,我們會想要的是一個「能獨立走出鏡子」的自己(Deep Copy),擁有完全不同的記憶體、不同的命運。
Shallow Copy 只複製外層,裡面參考到的物件還是共用同一份Deep Copy 會連內層參考物件一起複製,整包都變成新的
假設有這個類別
1234567891011121314151617public class Person{ public string Name { get; set; } public Address Address { get; set; & ...
Asynchronous Programming - 第七章:非同步之林:執行緒的四季輪迴
forestMain ThreadWorker ThreadsI/O Completion ThreadsCustom Thread「人力底線」與「人力上限」「ThreadPool 實驗summary在這片名為非同步之林的廣闊森林裡,藏著一家智慧餐廳。這間餐廳一天到晚接單不斷,每張訂單都是一個任務,廚房裡的人力有限,卻得讓所有客人都吃得快又好、不讓誰在門口久等,還得同時兼顧廚房資源的高效運用。
這家餐廳裡,有忙碌的櫃台接待員(Main Thread),有後廚大廚團隊(Worker Threads),有專門通知外送到達的取餐小組(I/O Completion Threads),偶爾,老闆還會臨時請來私廚(Custom Thread),用一場又一場執行緒的調度,撐起這座非同步之林裡飲食服務
🎵 Main Thread = 櫃台接待員負責第一時間接待客人、記錄每張訂單、回答客人問題。櫃台小姐(Main Thread)不能被卡住,一卡住,後面來的客人全部排隊大塞車!所以櫃台只是登記完,馬上就把訂單丟給後廚(ThreadPool)去做。
✅ 在 ASP.NET 裡,Ma ...
Asynchronous Programming - 第八章:一座池子的呼吸
一座池子的呼吸Task.Run 觀察 ThreadPool 的重複使用Starvation-Avoidance Mechanism 怕你餓機制ThroughputClimbing Heuristic - 爬山捷思法為什麼增加 Threads 並不一定帶來更高 Throughput?實驗一.實驗設計實驗一. 結果觀察實驗二.開頭即設定 200 條最低執行緒數量實驗三.實驗設計實驗三.觀察實驗結果summary在雲端深處,棲息著一個無形的池子,我們稱它為 ThreadPool,它不眠不休,日夜吞吐無數任務,是城市裡最沉默卻最可靠的工廠。每一個建立 Task 的瞬間,就像把工作單投入池子,任它激起層層漣漪,有人接手、有人閒置、有人待命
我們在這裡低聲詠唱,希望當高峰來臨,池子能無限擴張,當潮水退去,池子也能自我收束,忠實而溫順,既不餓死任務,也不浪費資源。當你想起這座池子,它從未離開,只是默默在背後,調度著一切的並行與秩序12345678910111213141516171819202122232425262728293031323334353637void Main(){ Tas ...
IEnumerable
🐛 Enumerator & Enumerable
Enumerator就是一個「游標(cursor)」,可以指向序列中的某一筆資料,並且知道「怎麼移到下一筆」、「現在這一筆是誰」。
是一個「讀取器」,負責「一筆一筆往前走」,只能唯讀 (read-only)、往前走 (forward-only)
實作的定義是
MoveNext() - 移到下一筆,回傳是否還有資料
Current - 取得目前資料
Reset() - 回到初始狀態(很少用)
介面:IEnumerator、IEnumerator
Enumerable就是一個「序列的抽象描述」,它本身不是游標,但是它可以「生出一個 Enumerator」來幫你走訪它。
是一個「集合的抽象表示」,它不是游標,不會自己動,但它要能生出 Enumerator,讓你真的能走訪它
實作的定義是
GetEnumerator()
介面:IEnumerable、IEnumerable
🐛 IEnumerable & IEnumerator若希望資料集合類別具有走訪能力,需要實作 IEnumerable 以及 IEn ...
Deferred Execution - 延遲的智慧
延遲執行(Deferred Execution)
他是一種耐心的智慧 —— 明明寫下一段 Code,卻不急著執行,彷彿在等待一個更合適的時機 !?
延遲執行(Deferred Execution)
幫助你在被某句話刺到時,第一反應不是想要立刻回嘴、發怒或做出回應。不選擇這種「立即執行」的行為,防止你在關係上造成傷害或是事後後悔
延遲執行(Deferred Execution)
讓我們理解,重大決定前需要沉澱期,轉職、搬家、投資、進入一段關係…… 不適合因為他人的壓力就出發立即執行
而創意與靈感的生成過程,很多時候你以為自己沒有靈感,其實是「狀態機還沒執行」。你已經把表達式建好了,放著沒動,等到靈感來臨時,才會開始真正地「MoveNext()」。
我們不是缺靈感,只是活不夠久,讓它進入可被遍歷的狀態
靈感的延遲執行人生就是一段靈感蒐集箱
1234567891011121314151617181920212223242526public class InspirationCollector : IEnumerab ...
IEnumerable, ICollection, IList and List – Which One To Use?
🐛 IEnumerableIEnumerable 是所有集合的基礎款,ICollection 繼承 IEnumerable,IList 繼承 ICollection,而我們常用的 List 就是 IList 的實作。所以 IEnumerable 相當於阿嬤,要敬老尊賢,或者也可以想像你訂閱了微軟的集合使用基礎方案 : IEnumerable。
基於這個基礎方案我們獲得這些功能:
可以用 foreach 逐筆處理(走訪抽象)。123IEnumerable<string> names = new[] { "Ann", "Bob", "Cindy" };foreach (var n in names) Console.WriteLine(n);
支援延遲執行(LINQ-to-Objects 的 Where/Select/Take)12345var data = Enumerable.Range(1, 1_000_000); // 還沒算var firstFive ...
IEnumerable<T> and IQueryable<T>
IQueryable在 IDE 中寫好的 IQueryable 只是 “查詢狀態”,此時還沒執行資料庫的查詢,因此不會有資料載入記憶體的行為。若指派某些會得到 “明確結果” 的 function,如 Count ()、ToList () 等,此時才會執行 SQL 查詢指令,取得查詢結果。IQueryable 介面會將 Expression 傳遞給 Provider,由 Provider 轉譯成 T-SQL 後,從 DB 中取得資料,得到 “明確結果”
1234567891011// 此時的data是"查詢狀態",資料還未載入記憶體中。IQueryable<Book> Qdata = dbContext.Book;// 在定義變數時加入條件式,也不會將"查詢狀態"載入記憶體中。IQueryable<Book> filterQdata = dbContext.Book.Where(x => x.Id == 1);//下面兩行程式才會執行SQL指令,並將查詢的資料載入記憶體中。var book = filterData.T ...











