2010-01-07 169 views
28

請原諒我,如果這是一個愚蠢的問題,我承認我沒有想太多。什麼時候使用回調而不是c#中的事件?

但是,當你喜歡使用回調(即傳入Func或Action)而不是暴露和使用事件?

UPDATE

是什麼促使這個問題是以下問題:

我有一個ThingsHandler類, 可以與ThingEditor關聯。 的ThingsHandler處理的 事情的清單,知道他們的訂單,其中之一是「當前」,當新 那些增加或刪除等

的ThingEditors可以只修改單個 事情。

的ThingsHandler需要提醒 的ThingEditor當用戶選擇 一個新的東西進行編輯,並ThingEditor需要提醒 ThingsHandler當用戶說 「完成」的 。

令我困擾的是這兩個類持有對方的引用 - 雖然我認爲這是不可避免的 - 或者在兩個方向上綁定事件。我想知道在一個方向上使用回調是否「更清潔」。

我懷疑這是一種設計模式,併爲我的無知(懶惰)謙恭地道歉。

回答

23

我使用回調在少數情況下,我知道,它只會不斷火一次,回調是具體到一個方法調用(而不是一個對象實例) - 例如,作爲回報異步方法的一部分。

靜態工具方法尤其如此(因爲您沒有實例,並且靜態事件在被粗心使用和被避免時是致命的),但是當然另一種選擇是創建一個類實例一個事件。

8

當一個對象希望接收單個通知(例如,異步數據讀取運行,然後調用結果)時,回調是很好的。

事件適用於可以由任意數量的監聽器接收的重複性通知。

3

就OO設計和類耦合而言,回調接口和事件之間沒有太大區別。但是,我更喜歡事件,他們是類需要向有興趣偵聽(通常是多個事物)和回調的用戶「喊」的事情,以及特定類請求異步操作的回調。

無論您使用什麼,請在整個代碼庫中一致地使用它們!

4

當我要調用一次函數或使用Lambda表達式時,我會使用FuncAction

活動可以註冊多次,有時候是理想的。有了回調,如果你想要多個回調,你必須實現回調的註冊系統。

3

一個例子是什麼時候回調應該返回一些東西。例如。 (笨示例):

public int Sum(Func<int> callbackA, Func<int> callbackB) { 
    return callbackA() + callbackB(); 
} 

public void UseSum() { 
    return sum(() => 10,() => 20); 
} 
21

一般來說,我使用回調,如果它是需要,而一個事件被使用時,它應該是可選的。 如果您希望始終有某些事情正在傾聽,請勿公開事件。

考慮以下幾點:

public class MyClass_Event 
{ 
    public event EventHandler MakeMeDoWork; 

    public void DoWork() 
    { 
     if (MakeMeDoWork == null) 
      throw new Exception("Set the event MakeMeDoWork before calling this method."); 
     MakeMeDoWork(this, EventArgs.Empty); 
    } 
} 

與:

public class MyClass_Callback 
{ 
    public void DoWork(EventHandler callback) 
    { 
     if (callback == null) 
      throw new ArgumentException("Set the callback.", "callback"); // better design 
     callback(this, EventArgs.Empty); 
    } 
} 

的代碼幾乎是一樣的回調可以作爲null傳入,但至少拋出的異常可能是更相關。

25

雖然迄今爲止的其他答案似乎是合理的,但我會採取更加哲學的方針。

一類是機制模型有一種特殊的東西在一個特定的領域。編寫一個類的內部細節以便將機制的實現細節與建模語義相混淆非常容易。我的意思一個簡單的例子:

class Giraffe : Mammal, IDisposable 
{ 
    public override void Eat(Food f) { ... } 
    public void Dispose() { ... } 
} 

通知我們如何混爲一談現實世界的事情被建模(長頸鹿是一種哺乳動物,長頸鹿吃的食物)與執行的細節(一長頸鹿的實例是可以用「使用」語句處理的對象)。我保證,如果你去動物園,你永遠不會看到一個長頸鹿與使用聲明處置。我們混淆了這裏的水平,這是不幸的。

我嘗試使用事件(和財產)作爲語義模型和使用回調方法(和字段)的機制的部分一部分。我會讓GaveBirth成爲長頸鹿的事件,因爲這是我們試圖捕捉的現實世界長頸鹿行爲模型的一部分。如果我有某種機制,比如說,我想實現一種散步樹遍歷算法,它可以走過長頸鹿的家族樹,並在每個樹上調用一個方法,那麼我會說這顯然是一種機制,而不是一部分並將其作爲一個回調,而不是試圖將其放入事件模型中。

+2

該死,你讓我的大腦再次受到傷害:)在我目前的代碼中,這些類遠離現實世界中的任何東西,我不知道我會從哪裏開始...(查看更新後的問題) – Benjol 2010-01-08 06:42:43

+3

好的答案,並總結:事件是通知(生下),回調是請求(吃食物)。將此與現實世界相關聯,你會得到一個用長頸鹿作爲對象的用例圖,用戶作爲動物處理程序(或者爆米花把它穿過酒吧的小孩) – Codesleuth 2010-01-08 09:23:55

+0

不僅難以消化,而且很難翻譯..最終它是值得的!謝謝埃裏克。 – 2013-12-09 22:40:45

0

嗯,我認爲他們是同樣的事情。有許多不同的技術術語來命名不同語言中的相同概念或事物。

那麼,你是什麼意思「回調」或「事件處理程序」?

根據MSDN:回調函數是託管應用程序中的代碼,可幫助非託管DLL函數完成任務。

而且,MADN也介紹了它們之間的區別。click here

回調是允許框架通過委託回調用戶代碼的擴展點。這些委託通常通過方法的參數傳遞給框架。

事件是回調的一種特殊情況,它支持提供委託(事件處理程序)的方便和一致的語法。此外,Visual Studio的語句完成和設計師提供使用基於事件的API

也有幫助,在一些書籍,如this book,筆者似乎說與MSDN同樣的事情。

因此,在我看來,你不能說在C#中使用回調而不是事件。

相關問題