2010-01-07 139 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#中使用回调而不是事件。

相关问题