Search code examples
c#eventsdelegateslistener

Omit sender of delegates


Is it possible to send reference of 'sender' without specifying it explicitly as a parameter in delegate-based event handling?

I have a internal class which raises some events and I want to call the events explicitly for test purposes.

public class Manager {
    public class DataStruct {
        public int Id { get; private set; }
        public event EventHandler Event1; // Can't be called by other classes
        public void fireEvent1(Event1();} // So another caller...

        // Delegates *can* be called by other classes
        public delegate void DelegateHandler(DataStruct sender);
        public DelegateHandler NewEvent;

        public void DelegateHandler(DataStruct sender) {
            MessageBox.Show(string.Format(
                "{0} raises event", sender.Id));
        }
    }
}

// Form1 ///////////////////////////////////////////////////////////////////
partial class Form1 {
    Manager.DataStruct dsRaiser, dsListener;

    private void Form1_Load(object sender, EventArgs e) {
        dsRaiser.Event1 += dsListener.SOME_HANDLER;
        dsRaiser.NewEvent += dsListener.DelegateHandler;
    }
    private void button1_Click(object sender, ...) {
        dsRaiser.fireEvent1(); // No argument needed but fireEvent1, not Event1().
    }
    private void button2_Click(object sender, ...) {
        dsRaiser.NewEvent(dsRaiser); // Way to omit parameter dsRaiser?
    }        
//////////////////////////////////////////////////////////////////////////

Solution

  • If your handler method needs to use the sender's reference, then you HAVE to pass that reference. If not, just declare a void parameterless delegate, like Action.

    But when thinking of events, that parameter should be passed by the class that raises the event itself. (Remember events are not meant to be called from outside).

    So, if you really want to use a simple delegate instead of an event, you will have to pass the parameters. If you need the sender, you will need to do exactly what you did with the event: create a method to "raise" the delegate, and in that method you pass this as the sender.

    But considering you have to do exactly the same thing in both cases, I'd surely use the event.

    public class DataStruct {
        public int Id { get; private set; }
        public event EventHandler Event1; // Can't be called by other classes
    
        // you need to pass those parameters to the event when called.
        public void fireEvent1{Event1(this, new EventArgs());} 
    
        // Delegates *can* be called by other classes, but only with all parameters passed.
        public delegate void DelegateHandler(DataStruct sender);
        public DelegateHandler NewEvent;
    
        // To avoid passing parameters, you need to do exactly what you did with the event
        public void RaiseDelegate() { NewEvent(this); }
    
        public void DelegateHandler(DataStruct sender) {
            MessageBox.Show(string.Format(
                "{0} raises event", sender.Id));
        }
    }