.NET 平臺的新手開發人員通常會在選擇基於 delegates 的設計或基於 events的設計時感到苦惱。 選擇委派或事件經常是困難的,因為這兩種程式語言的功能很相似。 事件甚至使用委派的語言支援來建置。 事件處理器的宣告會定義一個委派型別。
兩者都提供延遲綁定場景:它們使元件能夠在運行時通過呼叫僅在運行時才知曉的方法進行通訊。 它們都支援單一和多個訂閱者方法。 您可能會發現這些詞彙被稱為單播和多播支援。 兩者都支援類似的語法來增加和移除處理程序。 最後,引發事件並呼叫委派時,會使用完全相同的方法呼叫語法。 它們甚至都支援相同的 Invoke() 方法語法,以搭配 ?. 運算子使用。
有了所有這些相似之處,很難判斷使用時機。
接聽事件是選擇性的
判斷應該使用哪種語言功能時,最重要的考慮因素是是否必須有附加的訂閱者。 如果您的程式代碼必須呼叫訂閱者所提供的程式代碼,則當您需要實作回呼時,應該使用以委派為基礎的設計。 如果您的程式代碼可以在不呼叫任何訂閱者的情況下完成其所有工作,您應該使用以事件為基礎的設計。
請考慮本節期間建置的範例。 您使用 List.Sort() 建置的程式碼必須提供比較器函式,才能正確排序元素。 LINQ 查詢必須提供委派,才能判斷要傳回的元素。 兩者都使用透過委派建立的設計。
請考慮 Progress 事件。 它會報告工作的進度。 工作會繼續進行,無論是否有任何聽眾。
FileSearcher 是另一個範例。 它仍然會搜尋並找到所有所尋找的檔案,即使在沒有任何事件訂閱者附加的情況下也一樣。 即使沒有訂閱者接收事件,使用者介面控制項仍可正常運作。 兩者都使用以事件為基礎的設計。
傳回值需要委派
另一個考慮是您想要用於委派方法的方法原型。 如您所見,用於事件的委派都有 void 傳回類型。 有慣用語可建立事件處理程式,其會透過修改事件自變數對象的屬性,將資訊傳回事件來源。 雖然這些慣用語確實有效,但跟從方法中返回值相比,並不那麼自然。
請注意,這兩種啟發式通常都存在:如果您的委派方法返回值,它會以某種方式影響演算法的運作。
事件具備私有調用
除了包含事件的類別以外的其他類別只能新增和移除事件監聽器;只有包含事件的類別可以觸發該事件。 事件通常是公用類別成員。 相較之下,委派通常會以參數的形式傳遞,並且如果還儲存的話,會被作為私有類別成員儲存。
事件監聽器通常有較長的存留期
事件監聽器的較長存活時間是稍微弱一點的理由。 不過,當事件來源在很長一段時間內引發事件時,您可能會發現事件型設計更為自然。 您可以看到許多系統上UX控制件的事件型設計範例。 訂閱事件之後,事件來源就可以在程序的整個存留期內引發事件。 (當您不再需要時,您可以取消訂閱活動。)
與許多委託型設計相比,其中委託用作方法的參數,且該委託在方法返回後不再使用。
仔細評估
上述考慮並非嚴格不變的規則。 相反地,它們代表可協助您決定最適合您特定使用方式的選擇的指引。 因為它們很類似,您甚至可以同時建立原型,並考慮使用哪一個比較自然。 兩者都妥善處理延遲繫結的情況。 使用最能傳達設計效果的。