我可以说事件与代表之间的关系采用复合模式吗? [英] Can I say that the relation between events and delegates adopts composite pattern?

查看:48
本文介绍了我可以说事件与代表之间的关系采用复合模式吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个事件可以包含许多使用 delegate 定义的处理程序,我目前的理解是委托只是函数指针的抽象.由于与 delegate 类型关联的 event 可以向其中添加/删除许多委托,并且复合模式将复合对象与终端对象相同,因此想法是:

An event can contain many handlers which are defined using delegate, my current understanding is that delegate is just an abstraction of function pointer. Since an event, which associated with a delegate type, can add / remove many delegates into it, and composite pattern treats a composite object the same as the terminal object, so the idea is:

composite.onTriggered();
// Internally:
// foreach(handler in composite)
// {
//     handler.onTriggered();
// }

依次调用由 composite 管理的每个处理程序.

will in turn call every handlers managed by the composite.

但是,似乎公共事件EventHandler ThresholdReached 没有定义组合,请参见下面的代码中的我的评论

But it seems like public event EventHandler ThresholdReached does not define a composite, see my comment in the code below

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
}

我在抽象层面上对这个想法是否正确?如果不能,您可以提供任何更正吗?

Am I correct about the idea in abstract level? If not could you provide any correction(s)?

推荐答案

直接回答您的问题,我会说:不,事件与采用复合模式的代表之间没有关系.代表设计是,它遵循复合模式.没有事件.(此外,请注意您不需要使用事件来利用委托.(请参见下面的 DelegateBased ))(我将回答您对"这条线的末端?"作为结尾注释)

Directly answering your question, I would say: No, there is no relation between events and delegates adopting the composite pattern. Delegates design yes, it follows the composite pattern. Events not. (Moreover, notice that you do not need events to take advantage of delegates. (see DelegateBased bellow)) (I will answer your comment about "So what's the point of this line?" at the end as a side note)

尽管如此,委托类型本身遵循复合方法,即"复合模式描述了一个对象组,其处理方式与同一个对象类型的单个实例.".

Nevertheless, the Delegate type itself follows the composite approach in terms that "The composite pattern describes a group of objects that are treated the same way as a single instance of the same type of object.".

反过来,正如@ Flydog57和@ mark-seemann已经提到的那样,.NET事件模型遵循观察者模式.

In turn, as @Flydog57 and @mark-seemann have already mentioned the .NET event model follows the observer pattern.

事件和委托之间的关系认为,可能需要事件声明 为委托类型( TypeSpec ),具体说明如下 ECMA的 II.18定义事件部分-335(CLI)I至VI分区(标准):

The relation between Events and Delegates regards the Event declaration that may require a Delegate type (the TypeSpec), as it is stated in the section II.18 Defining events of ECMA-335 (CLI) Partitions I to VI (the standard):

在典型用法中,TypeSpec(如果存在)会标识一个委托,该委托的签名与传递给事件的fire方法的参数匹配.

In typical usage, the TypeSpec (if present) identifies a delegate whose signature matches the arguments passed to the event’s fire method.

为清楚起见,请检查以下两个等效示例,其中 EventBased 使用没有委托字段的事件,而 DelegateBased 使用没有事件的委托字段.请注意,我说的是代理字段代理类型.她们不一样.这两个示例都需要一个代理类型,对于该示例,该类型声明如下:

To make it clear, check the following two equivalent examples where EventBased uses events without a delegate field and DelegateBased uses a delegate field without events. Notice that I say distinctly delegate field or delegate type. They are not the same. Both examples need a delegate type which is declared as the following for this example:

delegate void Observer();

您可以使用以下两个示例来运行这两个示例:

You may run both examples with:

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

接下来,根据

Next, the two implementations of EventBased and DelegateBased that use names according to the example of 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
  }
}


关于您的评论:


Regarding your comment about:

EventHandler handler = ThresholdReached; // So what's the point of this line?
handler?.Invoke(this, e);

杰弗里·里希特(Jeffrey Richter)在其杰作《通过C#进行Clr》中明确指出了它的原因.第11章中的事件-以线程安全的方式引发事件"中的事件(请参见 NewMail 作为示例的 ThresholdReached ),其中指出:

The reason it is clearly identified by Jeffrey Richter in its masterpiece "Clr via C#" in Chapter 11 - Events at "Raising an Event in a Thread-Safe Way" (see the NewMail as the ThresholdReached of your example) where it states:

OnNewMail 方法的问题是线程可以看到 NewMail 不为null,然后在调用 NewMail 之前,另一个线程可以从链中删除委托,从而产生 NewMail null ,从而导致引发 NullReferenceException .

The problem with the OnNewMail method is that the thread could see that NewMail is not null, and then, just before invoking NewMail, another thread could remove a delegate from the chain making NewMail null, resulting in a NullReferenceException being thrown.

这篇关于我可以说事件与代表之间的关系采用复合模式吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆