Home > Back-end >  How to pass an event through classes in C#
How to pass an event through classes in C#

Time:08-20

Here are 3 C# classes :

class StartClass
{
  event StartEvent;
  // some code
class MidClass
{
  private StartClass _startClass;
  public MidClass (StartClass startClass)
  {
    _startClass = startClass;
  }
  // some code
class EndClass
{
  private MidClass _midClass;
  public EndClass (MidClass midClass)
  {
    _midClass = midClass;
  }
  // some code

  public void OnStartEvent () 
  {
    // code to be executed on StartEvent called
  }

What's best way if you want to attach EndClass.OnStartEvent listener to StartClass.StartEvent event ?

I think the best way would be to create a MidClass.StartEvent property referencing StartClass.StartEvent event in order to be able to attach the listener in EndClass doing _midClass.StartEvent = OnStartEvent;. Am I right ? How to attach StartClass.StartEvent to MidClass.StartEvent ?

CodePudding user response:

In C# an event is much like a property. It is a wrapper for a delegate. Usually we are using auto-implemented events. But we can expand them. Properties have get and set accessors. Events have add and remove accessors.

class MidClass
{
    private readonly StartClass _startClass;
    public MidClass (StartClass startClass)
    {
        _startClass = startClass;
    }

    public event EventHandler StartEvent
    {
        add => _startClass.StartEvent  = value;
        remove => _startClass.StartEvent -= value;
    }
}

Here, we create a StartEvent in MidClass that is a wrapper for the corresponding event in StartClass. StartClass.StartEvent must be public.

The advantage of this approach is that an event handler subscribing to MidClass.StartEvent will directly be attached to StartClass.StartEvent, with no intermediate call occurring when the event is risen.

One word to naming. Methods named OnEventName are usually used to raise events, while methods named PublisherName_EventName are used for event handlers.

class StartClass
{
    public event EventHandler StartEvent;

    private virtual void OnStartEvent()
    {
        StartEvent?Invoke(this, EventArgs.Empty);
    }
}

class EndClass
{
    private MidClass _midClass;

    public EndClass (MidClass midClass)
    {
        _midClass = midClass;
        _midClass.StartEvent  = MidClass_StartEvent;
    }

    private void MidClass_StartEvent (object sender, EventArgs e)
    {
        // Code to be executed when StartEvent is triggered
    }
}

CodePudding user response:

I think the best way would be to create a MidClass.StartEvent property referencing StartClass.StartEvent event in order to be able to attach the listener in EndClass doing _midClass.StartEvent = OnStartEvent;. Am I right?

If you want to keep the reference to StartClass a private implementation detail of MidClass: Yes, implementing a "proxy" StartEvent in MidClass is the right way to do it.

How to attach StartClass.StartEvent to MidClass.StartEvent ?

By attaching a listener to _startClass.StartEvent which just raises the corresponding event in MidClass:

class MidClass
{
    public event EventHandler StartEvent;

    private readonly StartClass _startClass;
    public MidClass(StartClass startClass)
    {
        _startClass = startClass;
        _startClass.StartEvent  = (sender, e) => this.StartEvent?.Invoke(this, e);
    }

    ...
}

Note that I also added the readonly modifier to _startClass: If the value of _startClass changes during the lifetime of MidClass, you need to detach your event handler from the old reference and attach it to the new reference.

  •  Tags:  
  • c#
  • Related