请原谅我,如果这是一个愚蠢的问题,我承认我没有多想过。
但是你喜欢何时使用回调(即传入Func或Action),而不是暴露和使用事件?
更新
这个问题的动机是以下问题:
我有一个ThingsHandler类,它 可以与ThingEditor相关联。 ThingsHandler处理一个列表 事情,了解他们的秩序,哪一个是“当前的”,什么时候是新的 添加或删除等。
ThingEditors可以修改单个 事情。
ThingsHandler需要提醒 用户选择时的ThingEditor 一个新的东西编辑,和 ThingEditor需要警告 当用户说时,ThingsHandler '完成'。
困扰我的是让这两个类相互引用 - 虽然我猜这是不可避免的 - 或者在两个方向上绑定事件。我想知道在一个方向上使用回调是否“更清洁”。
我怀疑这有一种设计模式,并为我的无知(和懒惰)谦卑地道歉。
答案 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表达式时,我会使用Func
或Action
。
事件可以多次注册,有时是理想的。如果你需要多个回调函数,那么必须为回调实现一个注册系统。
答案 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#中的事件。