一个事件可以包含许多使用 delegate
定义的处理程序。 ,我目前的理解是委托(delegate)只是函数指针的抽象。由于 event
,与 delegate
相关联类型,可以在其中添加/删除许多委托(delegate),并且复合模式将复合对象视为终端对象,因此想法是:
composite.onTriggered();
// Internally:
// foreach(handler in composite)
// {
// handler.onTriggered();
// }
将依次调用 composite
管理的每个处理程序.但似乎
public event EventHandler ThresholdReached
没有定义复合,请参阅下面代码中的我的评论class Counter
{
public event EventHandler ThresholdReached;
protected virtual void OnThresholdReached(EventArgs e)
{
EventHandler handler = ThresholdReached; // So what's the point of this line?
handler?.Invoke(this, e);
// Why not just:
// ThresholdReached?.Invoke(this, e);
}
// provide remaining implementation for the class
}
我对抽象级别的想法是否正确?如果不能,您能否提供任何更正?
最佳答案
直接回答你的问题,我会说:不,没有关系 在采用复合模式的事件和委托(delegate)之间。 委托(delegate)设计是 ,它遵循复合模式。 事件不是 . (此外,请注意 您不需要事件来利用委托(delegate)。(见 DelegateBased
下文))(我将在最后回答您关于“那么这条线的意义何在?”的评论作为旁注)
尽管如此,委托(delegate)类型它本身遵循复合方法,即“复合模式描述了 对象组处理方式与 相同单实例属于同一类型的对象。”。
反过来,正如@Flydog57 和@mark-seemann 已经提到的.NET 事件模型遵循观察者模式。
事件和委托(delegate)之间的关系关于 事件声明这可能需要一个委托(delegate)类型(TypeSpec
),如第 II.18 节定义 ECMA-335 (CLI) Partitions I to VI 的事件中所述(标准):
In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.
为了清楚起见,请检查以下两个等效示例,其中
EventBased
使用没有委托(delegate)字段和 DelegateBased
的事件使用没有事件的委托(delegate)字段。请注意,我明确表示委托(delegate)字段或委托(delegate)类型。它们是不相同的。这两个示例都需要一个委托(delegate)类型,在此示例中声明如下:delegate void Observer();
您可以使用以下命令运行这两个示例:var subject = new DelegateBased(); // replace it with: var subject = new EventBased();
Observer foo = () => Console.Write("Foo");
Observer bar = () => Console.Write("Bar");
subject.RegisterObserver(foo); // subject.Caller += foo;
subject.RegisterObserver(bar); // subject.Caller += bar;
subject.Notify(); // prints: FooBar
Console.WriteLine();
subject.UnregisterObserver(foo); // subject.Caller -= foo;
subject.Notify(); // prints: Bar
接下来是EventBased
的两种实现和 DelegateBased
根据 Observer Pattern in Wikipedia 的示例使用名称class EventBased {
private List<Observer> observers = new List<Observer>();
public event Observer Caller {
add { RegisterObserver(value); }
remove { UnregisterObserver(value); }
}
public void Notify() { foreach (var caller in observers) caller(); }
public void RegisterObserver(Observer val) { observers.Add(val); }
public void UnregisterObserver(Observer val) { observers.Remove(val); }
}
class DelegateBased {
private Observer observers; // delegate field without events
public void Notify() { observers(); }
public void RegisterObserver(Observer val) {
observers = (Observer) Delegate.Combine(observers, val); // <=> observers += val
}
public void UnregisterObserver(Observer val) {
observers = (Observer) Delegate.Remove(observers, val); // <=> observers -= val
}
}
关于您的评论:
EventHandler handler = ThresholdReached; // So what's the point of this line?
handler?.Invoke(this, e);
Jeffrey Richter 在其杰作“Clr via C#”在第 11 章 - “以线程安全的方式引发事件”中的事件(参见 NewMail
作为示例的 ThresholdReached
)中明确指出了它的原因,其中它指出:The problem with the
OnNewMail
method is that the thread could see thatNewMail
is not null, and then, just before invokingNewMail
, another thread could remove a delegate from the chain makingNewMail
null
, resulting in aNullReferenceException
being thrown.
关于c# - 我可以说事件和委托(delegate)之间的关系采用复合模式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64906053/