何时使用回调代替c#中的事件?

时间:2010-01-07 12:57:07

标签: c# events

请原谅我,如果这是一个愚蠢的问题,我承认我没有多想过。

但是你喜欢何时使用回调(即传入Func或Action),而不是暴露和使用事件?

更新

这个问题的动机是以下问题:

  

我有一个ThingsHandler类,它   可以与ThingEditor相关联。   ThingsHandler处理一个列表   事情,了解他们的秩序,哪一个是“当前的”,什么时候是新的   添加或删除等。

     

ThingEditors可以修改单个   事情。

     

ThingsHandler需要提醒   用户选择时的ThingEditor   一个新的东西编辑,和   ThingEditor需要警告   当用户说时,ThingsHandler   '完成'。

困扰我的是让这两个类相互引用 - 虽然我猜这是不可避免的 - 或者在两个方向上绑定事件。我想知道在一个方向上使用回调是否“更清洁”。

我怀疑这有一种设计模式,并为我的无知(和懒惰)谦卑地道歉。

8 个答案:

答案 0 :(得分:28)

虽然到目前为止其他答案看似合理,但我会采取更具哲学性的方法。

类是机制模型特定域中的特定类型的东西。在编写类的内部细节以将机制实现细节与正在建模的语义混淆时,这非常容易。我的意思的一个简短例子:

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

注意我们如何将现实世界的物体(长颈鹿是一种哺乳动物,长颈鹿吃食物)与实施的细节混为一谈(长颈鹿的一个实例是一个可以被处理掉的物体“使用”声明)。我保证,如果你去动物园,你将永远不会看到长颈鹿被处理使用声明。我们把这里的水平搞混了,这是不幸的。

我尝试将事件(和属性)用作语义模型的一部分,并使用回调方法(和字段)作为机制的一部分。我会让GaveBirth成为长颈鹿的事件,因为这是我们试图捕捉的真实世界长颈鹿行为模型的一部分。如果我有一些机制,比如说,我想实现一个顺序遍历树遍历算法,它走遍了长颈鹿的家谱,并在每一个上调用一个方法,那么我会说这显然是一个机制,而不是一部分该模型,并使其成为一个回调,而不是试图将其塞进事件模型中。

答案 1 :(得分:26)

我在一些情况下使用回调,我知道它只会永远一次,并且回调是特定于单个方法调用(而不是对象) instance) - 例如,作为异步方法的返回部分。

对于静态实用程序方法尤其如此(因为您没有实例,并且在不小心使用并且要避免时静态事件是致命的),但当然另一种选择是创建一个具有事件而不是。

答案 2 :(得分:23)

一般情况下,如果需要,我会使用回调,而当应该是可选项时会使用事件。 如果您希望总能听到某些事情,请不要公开活动。

请考虑以下事项:

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传递相同,但至少抛出的异常可能更相关。

答案 3 :(得分:9)

当一个对象希望收到单个通知时(例如,运行异步数据读取,然后使用结果调用您),回调就很好。

事件适用于可由任意数量的侦听器接收的重复通知。

答案 4 :(得分:4)

在OO设计和类耦合方面,回调接口和事件之间没有太大区别。

但是,我更喜欢这样的事件:类是需要对那些有兴趣倾听的人(通常是多件事)以及特定类请求异步操作的回调“大喊大叫”。

无论您使用什么,都要在整个代码库中一致地使用它们!

答案 5 :(得分:4)

当我要调用该函数一次或使用Lambda表达式时,我会使用FuncAction

事件可以多次注册,有时是理想的。如果你需要多个回调函数,那么必须为回调实现一个注册系统。

答案 6 :(得分:3)

一个例子是回调应该返回的东西。例如。 (愚蠢的例子):

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

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

答案 7 :(得分:-1)

嗯,我认为它们是一样的。有许多不同的技术术语来命名不同语言中的相同概念或事物。

那么,你是什么意思&#34;回调&#34;或&#34;事件处理程序&#34;?

根据MSDN:回调函数是托管应用程序中的代码,可帮助非托管DLL函数完成任务。

而且,MADN还向我们介绍了它们之间的区别。click here

  

回调是扩展点,允许框架通过委托回调用户代码。这些代理通常通过方法的参数传递给框架。

     

事件是回调的一种特殊情况,它支持提供委托(事件处理程序)的方便且一致的语法。此外,Visual Studio的语句完成和设计人员提供了使用基于事件的API的帮助

此外,在某些书籍中,例如this book,作者似乎对MSDN说了同样的话。

因此,在我看来,你不能说使用回调代替C#中的事件。