在c#中何时使用回调而不是事件?

在c#中何时使用回调而不是事件?,c#,events,C#,Events,如果这是一个愚蠢的问题,请原谅,我承认我没怎么想过 但是,与公开和使用事件相比,您什么时候更喜欢使用回调(即传入Func或Action) 更新 引发这个问题的原因是以下问题: 我有一门ThingsHandler的课 可以与ThingEditor关联。 ThingsHandler处理一个 事物,知道它们的顺序,哪一个是“当前的”,当是新的 添加或删除等 ThingEditor可以只修改单个 事情 这东西需要提醒你 当用户选择ThingEditor时,ThingEditor 要编辑的新内容,以及 T

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

但是,与公开和使用事件相比,您什么时候更喜欢使用回调(即传入Func或Action)

更新

引发这个问题的原因是以下问题:

我有一门ThingsHandler的课 可以与ThingEditor关联。 ThingsHandler处理一个 事物,知道它们的顺序,哪一个是“当前的”,当是新的 添加或删除等

ThingEditor可以只修改单个 事情

这东西需要提醒你 当用户选择ThingEditor时,ThingEditor 要编辑的新内容,以及 ThingEditor需要提醒 当用户说 “完成”

让我烦恼的是,这两个类相互引用——虽然我想这是不可避免的——或者绑定到两个方向的事件。我想知道在一个方向上使用回调是否“更干净”


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

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


静态实用程序方法尤其如此(因为您没有实例,如果不小心使用静态事件,静态事件是致命的,需要避免),但当然,另一个选项是使用事件创建类实例。

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


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

就OO设计和类耦合而言,回调接口和事件之间没有太大区别

但是,我更喜欢那些类需要“呼喊”给有兴趣监听的人的事件(通常是多个事件)和特定类请求异步操作的回调


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

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


事件可以注册多次,这有时是理想的。对于回调,如果需要多个回调,则必须为回调实现注册系统。

一个示例是回调应该返回某些内容。例如(愚蠢的示例):

public int Sum(Func callbackA,Func callbackB){
返回callbackA()+callbackB();
}
公共用途总额(){
返回和(()=>10,()=>20);
}

通常,如果回调是必需的,我会使用回调,而如果事件是可选的,则会使用事件。 如果你希望总是有人在听,就不要暴露事件

考虑以下几点:

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

尽管到目前为止其他答案似乎合理,但我会采取更为哲学的策略

类是一种机制,用于对特定领域中的特定类型的事物进行建模。编写类的内部细节时,很容易将机制的实现细节与所建模的语义合并在一起。我的意思的简单示例如下:

class Giraffe : Mammal, IDisposable
{
    public override void Eat(Food f) { ... }
    public void Dispose() { ... }
}
请注意,我们是如何将正在建模的真实世界(长颈鹿是一种哺乳动物,长颈鹿吃食物)与实现细节(长颈鹿的实例是一个可以用“using”语句处理的对象)混为一谈的.我保证,如果你去动物园,你永远不会看到长颈鹿在使用声明中被处理。我们把级别弄混了,这很不幸


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

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

那么,“回调”或“事件处理程序”是什么意思

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

MADN还介绍了它们之间的区别

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

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

此外,在一些书中,例如,作者似乎对MSDN说了同样的话


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

Darn,你又让我的大脑受伤了:)在我当前的代码中,这些类与现实世界中的任何东西都相去甚远,我不确定从何处开始…(见更新的问题)答案很好,总结一下:事件就是通知(分娩),回调是请求(吃东西)。将其与现实世界联系起来,你会得到一个用例图
class Giraffe : Mammal, IDisposable
{
    public override void Eat(Food f) { ... }
    public void Dispose() { ... }
}