Delegates/Events are not sticking

xXZexxMooreXx

Member
Joined
Dec 28, 2014
Messages
5
Programming Experience
Beginner
I've been at it a week, and yet I feel worse off than when I heard about delegates and events. The biggest issue I'm having is that the videos and books do a real good job at presenting the syntax and basic ideas behind them, but the contrived examples are really killing me when it comes to being able to use them for myself.

I thought a good example of driving it two concepts home were a simple console based application that had a Person, Phone and SwitchBoard class. My thinking was that the Phone would publish two different events, one based on an outgoing call to the SwitchBoard, and one broadcast to a Person/Persons that are listening for the their phone to ring. Also, my thinking was that the SwitchBoard would publish an event for the proper phone on the other end.

I do believe I was able to make it work between the Phone and Person, but once throwing in the SwitchBoard, things went south from there.

C#:
    class Person
    {
        public Person(Phone p)
        {
            p.IncomingCallEvent += OnRecieveCall;
        }


        void OnRecieveCall()
        {
            Console.WriteLine("You're Phone Is Ringing...");
        }
    } 


    class Phone
    {
        public delegate void IncomingCallHandler();
        public event IncomingCallHandler IncomingCallEvent;


        public delegate void OutGoingCallHandler(Phone p);
        public event OutGoingCallHandler OutGoingCallEvent;


        public string Number { get; set; }


        public Phone(SwitchBoard sb)
        {
            sb.phoneDirectory.Add(this);
        }


        void OnCall()
        {
            if (IncomingCallEvent != null)
                IncomingCallEvent();
        }


        void OnOutGoingCall()
        {
            if (OutGoingCallEvent != null)
            {
                OutGoingCallEvent(this);
            }
        }
    }
    
    class SwitchBoard
    {
        public delegate void IncomingHandler();
        public event IncomingHandler IncomingEvent;


        public SwitchBoard(Phone p)
        {
            phoneDirectory = new List<Phone>();
            p.OutGoingCallEvent += OnIncomingCall;
        }


        public List<Phone> phoneDirectory;


        void OnIncomingCall(Phone phone)
        {
       
        }
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,144
Location
Sydney, Australia
Programming Experience
10+
First of all, let me review delegates and events in general and provide my take to make sure that we're on the same page.

Firstly, a delegate is an object that stores a reference to a method. You can think of delegates as special classes, which they are under the hood anyway. Where a class might have properties and each instance of that class might refer to specific data via those properties, a delegate has basically a single property that refers to a method rather than an object. Internally, that reference is basically the memory address at which that method resides, just as a reference to an object is the memory address of that object. When you invoke a delegate, it executes the method it has a reference to. The name is not just invented out of thin air. A delegate is generally a person who is authorised to perform an action or actions on behalf of another person or persons. For instance, each country sends a delegate to the UN and that delegate is authorised make decisions on behalf of that country. When a UN delegate votes on something at the UN it is in effect the country they are delegating for casting its vote, just a by invoking a C# delegate in one object, you are actually executing a method in another.

Events are basically a collection of delegate instances. When one object handles and event of a second object, what actually happens is the first object creates a delegate to its own method that will handle the event and passes that to the first object, which then adds the delegate to the collection for the event being handled. That's why registering an event handler uses the "+=" syntax: it is logically adding the specified delegate to a collection. When an object raises an event, what it actually does is get the collection of delegates for that event, loops through it and invokes each one.

For instance, when you add a Button named "button1" to a form and handle its Click event with a method named "button1_Click", you will see in the designer-generated code a line like this:
this.button1.Click += new System.EventHandler(this.button1_Click);
What that means is that the form is creating a delegate of type EventHandler that refers to its own button1_Click method and passing it to button1, which adds it to the collection of delegates that will be invoked when it raises its Click event. When the Button is clicked, it will invoke that delegate, thus executing the form's button1_Click method.

So, does that make things any clearer? As for defining and raising your own events, I suggest that you follow the Blog link in my signature below and check out my post on Custom Events. If you follow the advice in that post then you will make some changes to your code. If you still have issues after that, post back and I'll take a look at your new code.
 

xXZexxMooreXx

Member
Joined
Dec 28, 2014
Messages
5
Programming Experience
Beginner
I've spent some time reading your Custom Events blog post, and even though I didn't help me fix my example, it did show me some things that I haven't seen in any book or video.

Someone told me that the main problem in my example is the design itself, and if that is the case, then me using that example to learn the said topic is pointless unless the design is fixed. Below I'll just post the Phone class even though it may be pointless.

As a note, I'm no longer confident I'll be able to grasp this, and if you believe the same, then feel free to close/delete this post.

C#:
class Phone
    {
        public event EventHandler IncomingCall;
        public event EventHandler OutGoingCall;

        protected virtual void OnIncomingCall(EventArgs e)
        {
            if (IncomingCall != null)
                IncomingCall(this, e);
        }


        protected virtual void OnOutGoingCall(EventArgs e)
        {
            if (OutGoingCall != null)
                OutGoingCall(this, e);
        }
}
What is the proper way for the Person to subscribe to the Phone event? I wish I could help you help me, but my mind is so twisted it may not be worth your effort/time.
 
Last edited:

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,144
Location
Sydney, Australia
Programming Experience
10+
A Person object would have to have a reference to a Phone object of which to handle an event. The code of such a Person class might loop like this:
private Phone myPhone = new Phone();

public Person()
{
    myPhone.IncomingCall += myPhone_IncomingCall;
}

private void myPhone_IncomingCall(object sender, EventArgs e)
{
    // ...
}
Note that the IDE can help you write that code. If you just type `myPhone.IncomingCall += ` you can simply use the Tab key to first generate the delegate and then generate the event handler.
 

xXZexxMooreXx

Member
Joined
Dec 28, 2014
Messages
5
Programming Experience
Beginner
Okay, that is one of the challenges in my thinking I've been having. If the Person has to reference a Phone, then what happens when a person decides he doesn't want a Phone any more. It also makes me think that the Phone is actually part of the Person, instead of a separate entity. Contrast that with the example below:

C#:
class Phone
{
     private PhoneLCDScreen;
}

class PhoneLCDScreen
{
}
In the above example, the lcd screen is actually a separate entity, but connects to the Phone itself. Another way of saying it, it's part of the phone where as a Phone isn't part of a Person.

So, that means that I have a weak understanding of something that precedes delegates/events. Would you care to point that out to me, and if you have any posts regarding said weakness, could you list it?
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,144
Location
Sydney, Australia
Programming Experience
10+
Think about how it works in real life. You are a person and you have a phone. The phone isn't part of you but you still have the phone. You can't answer a phone that you don't know exists. The same goes for programming objects; a Person object can't handle an event of a Phone object that it doesn't know exists. The Phone object doesn't necessarily have to be assigned to a field or property of the Person object but, at the moment that the event handler is added, the Person object must have a reference to the Phone object. If it didn't, it could access the event to add the event handler. Here's an example where the reference exists at the time the event handler is added but not otherwise:
public void HandleIncomingCall(Phone myPhone)
{
    myPhone.IncomingCall += myPhone_IncomingCall;
}
 
private void myPhone_IncomingCall(object sender, EventArgs e)
{
    // ...
}
The Person object has a reference to Phone object for which it is handling the event only for the time that it is actually adding the event handler; not before and not after.
 

xXZexxMooreXx

Member
Joined
Dec 28, 2014
Messages
5
Programming Experience
Beginner
I actually think I see what you're saying. In the example you gave above, where you pass a Phone to HandleIncomingCall(Phone p), which I feel makes more sense to me, and I assume there is nothing wrong with it given that you used it that way. I think it's possible that I've made it more difficult than it really is.

I'm going to hit it some more and see what I can come up with. Thanks jmc.
 

xXZexxMooreXx

Member
Joined
Dec 28, 2014
Messages
5
Programming Experience
Beginner
This is what I've managed to come up with on this go:

C#:
class Person
    { 
        public void HandleIncomingCall(Phone p)
        {
            p.IncomingCall += p_IncomingCall;
        }


        void p_IncomingCall(object sender, EventArgs e)
        {
            Console.WriteLine("Phone is ringing...");
        }
    }


    class Phone
    {
        public event EventHandler IncomingCall;
        public event EventHandler OutGoingCall;


        public string PhoneNumber { get; set; }
        public string OutgoingNumber { get; set; }


        void OnIncomingCall(EventArgs e)
        {
            if (IncomingCall != null)
                IncomingCall(this, EventArgs.Empty);
        }


        void OnOutGoingCall(EventArgs e)
        {
            if (IncomingCall != null)
                OutGoingCall(this, EventArgs.Empty);
        }


        public void PlaceCall(string number)
        {
            OutgoingNumber = number;


            OnOutGoingCall(EventArgs.Empty);
        }
    }


    class SwitchBoard
    {
        List<Phone> phoneDirectory = new List<Phone>();


        public void AddPhoneToDirectory(Phone p)
        {
            if (!phoneDirectory.Exists(x => x.PhoneNumber == p.PhoneNumber))
            {
                phoneDirectory.Add(p);
                p.OutGoingCall += p_OutGoingCall;
            }
        }


        public void RemovePhoneFromDirectory(Phone p)
        {
            if (phoneDirectory.Exists(x => x.PhoneNumber == p.PhoneNumber))
            {
                Phone temp = phoneDirectory.First(x => x.PhoneNumber == p.PhoneNumber);
                temp.OutGoingCall -= p_OutGoingCall;


                phoneDirectory.Remove(temp);
            }
        }

        // I'm Stuck Here
        void p_OutGoingCall(object sender, EventArgs e)
        {
            Phone incomingPhone = (Phone)sender;


            if (phoneDirectory.Exists(x => x.PhoneNumber == incomingPhone.OutgoingNumber))
            {
                Phone targetPhone = phoneDirectory.First(x => x.PhoneNumber == incomingPhone.OutgoingNumber);


            }
        }
    }
As it stands now, I'm stuck at the commented section in the code. Once I pull out the targetPhone from the phoneDirectory, I'm not yet seeing how to use an event to call the targetPhone. The way I'm seeing it right now is that I'd need to have a public method in to accept a call, but that doesn't feel right because that means it would be exposed and anyone could call it.

Do you see any flaws in what I have this go around? Also, would you care to comment on whether or not I've made any progress?
 
Last edited:
Top Bottom