Methods are often described as actions that an object can do. For example, a List
class can add an item to itself or clear itself.
Events are often described as actions that happen to an object. For example, in a user interface, Button
has a Click
event, click being something that happens to a button.
Another way of thinking of events is a way of exchanging messages between two objects.
You have already seen the most common way to call or execute a method: use the dot syntax to access the method using its name. For example, Console.WriteLine
tells the Console
type to write out the message to the console window or terminal.
The other way to call or execute a method is to use a delegate. If you have used languages that support function pointers, then think of a delegate as being a type-safe method pointer. In other words, a delegate is the memory address of a method that matches the same signature as the delegate so that it can be safely called.
For example, imagine there is a method that must have a string
passed as its only parameter and it returns an int
:
public int MethodIWantToCall(string input) { return input.Length; // it doesn't matter what this does }
I could call this method directly like this:
int answer = p1.MethodIWantToCall("Frog");
Alternatively, I could define a delegate with a matching signature to call the method indirectly. Notice that the names of parameters do not have to match. Only the types of parameters and return values must match:
delegate int DelegateWithMatchingSignature(string s);
Now, I can create an instance of the delegate, point it at the method, and finally call the delegate (which calls the method!):
var d = new DelegateWithMatchingSignature(p1.MethodIWantToCall); int answer2 = d("Frog");
You are probably thinking, "What's the point of that?" Well, it provides flexibility.
We could use delegates to create a queue of methods that need to be called in order. Delegates have built-in support for asynchronous operations that run on a different thread for better performance. Most importantly, delegates allow us to create events.
Microsoft has two predefined delegates for use as events. They look like this:
public delegate void EventHandler(object sender, EventArgs e); public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
Add the following code to the Person
class. The code defines an event named Shout
. It also defines a field to store AngerLevel
and a method named Poke
. Each time a person is poked, their anger level increments. Once their anger level reaches three, they raise the Shout
event, but only if the event delegate is pointing at a method defined somewhere else in code, that is, not null:
// event public event EventHandler Shout; // field public int AngerLevel; // method public void Poke() { AngerLevel++; if (AngerLevel >= 3) { // if something is listening... if (Shout != null) { // ...then raise the event Shout(this, EventArgs.Empty); } } }
In Visual Studio 2017, in the Main
method, start typing the following code to assign an event handler:
harry.Shout +=
Notice the IntelliSense that appears when you enter the +=
operator, as shown in the following screenshot:
Press Tab. You will now see a preview of what Visual Studio would like to do for you, as shown in the following screenshot:
Press Enter to accept the name of the method.
Visual Studio 2017 inserts a method that correctly matches the signature of the event delegate. This method will be automatically called when the event is raised.
Scroll down to find the method Visual Studio 2017 created for you and delete the statement that throws NotImplementedException
.
In Visual Studio Code, you must write the method and assign its name yourself. The method should look like this. The name can be anything, but Harry_Shout
is sensible:
private static void Harry_Shout(object sender, EventArgs e) { }
In Visual Studio Code, in the Main
method, add the following statement to assign the method to the event:
harry.Shout += Harry_Shout;
In both Visual Studio 2017 and Visual Studio Code, add statements to the Harry_Shout
method to get a reference to the Person
object and output some information about them, as shown in the following code:
private static void Harry_Shout(object sender, EventArgs e)
{
Person p = (Person)sender;
WriteLine($"{p.Name} is this angry: {p.AngerLevel}.");
}
Back in the Main
method, add the following statements to call the Poke
method four times, after assigning the method to the Shout
event:
harry.Shout += harry_Shout;
harry.Poke();
harry.Poke();
harry.Poke();
harry.Poke();
Run the application. Note that Harry only gets angry enough to shout once he's been poked at least three times:
Harry is this angry: 3. Harry is this angry: 4.
3.145.35.194