Reference: The analysis is thorough! Enlightened
Events and delegation seem hard to understand,
This is because their usage is very different from common encoding methods,
For example, you usually write synchronization code and call a type method,
The result of method execution is displayed immediately, which is logical.
But in some cases,
The synchronization code may not meet the requirements,
Take a bus for example,
If the Traffic Control Center wants each bus to send a signal to itself when arriving at a site, it will be able to know the traffic conditions at any time,
When synchronous code is used, the public steam object must call the control center object,
In this case, two types are closely coupled.
Since other types need to respond to their own behaviors, it seems inevitable to call methods of their own types,
In synchronous code, it is difficult to avoid this close type call relationship.
The other difference is that in general, we only pass the attribute as a parameter to the method,
However, it is seldom considered to pass a method to another method.
We discard the difficult concepts of events and delegation in C # reference books,
Imagine a scenario to understand the use of events and delegation: There is an IT company,
The chairman does not want his employees to play games during work hours, but may not stare at every employee at all times,
Therefore, he wants to monitor employees in a new way:
If an employee violates regulations, a device or a specialized invigilator will automatically send a message to him, and the chairman of the board only needs to handle the incident.
Therefore, this use case is actually the interaction between the Chairman and employee,
The following code shows you how to use the delegate and event mechanism to implement this interaction:
First, we need to define a delegate type between the chairman class and the employee class to transfer events between the two,
This type is a monitoring device or an invigilator responsible for reporting:
Public delegate void DelegateClassHandle ();
The process of defining a delegate is similar to the definition of a method, but it does not have a method body.
To define a delegate, you must add the keyword delegate.
Since the definition delegate is actually quite a class, you can define the delegate anywhere in the definition class.
In addition, you can add general access modifiers such as public, private, and protected based on the delegate visibility.
The Return Value Type of the delegate is void, which does not indicate that the delegate type has a return value,
The return value type refers to the type of the Delegate's target function, that is, the return value of an event processing function entrusted by the delegate is the void type.
The code for creating an Employee class is as follows:
Public class Employee
{
Public event DelegateClassHandle PlayGame;
Public void Games ()
{
If (PlayGame! = Null)
{
PlayGame ();
}
}
}
The Employee class Employee code defines a DelegateClassHandle-type event PlayGame,
Its definition method is also very special. You must first use the keyword event to indicate that PlayGame is an event,
At the same time, you must declare that the delegate type of this event is DelegateClassHandle. The delegate object of this type will be responsible for notifying the event.
If an employee starts playing a game, it will execute the Games method, as long as this method is called,
A PlayGame event will be triggered, and the chairman of the board will receive a message about the event-someone is playing the game.
The Chairman class code is as follows. He has a method named Notify y to receive messages:
Public class Admin
{
Public void Policy ()
{
System. Console. WriteLine ("someone is playing game ");
}
}
How can I associate the PlayGame event of Employee ee with the Notify method of Admin?
You only need to bind events. The specific process is as follows:
Employee employee = new Employee ();
Admin admin = new Admin ();
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Employee. Games ();
Pay attention to the code bound to the event:
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Two classes are bound through DelegateClassHandle,
When the employee. Games method is called, the PlayGame event is triggered,
This event will be delegated to the admin's Notify method for handling, notifying the chairman of the board of directors that there are employees playing games during work hours.
However, the chairman of the board is not satisfied with this simple notification. He also wants to know who violates the regulations during work hours.
Obviously, the required parameters must be passed to the delegate object, which can be easily implemented.
Event parameters can be set to any type of data,
In the. NET Framework, the event parameter base class EventArgs is also provided for passing event data.
A Custom Event parameter class CustomeEventArgs is derived from the EventArgs class,
This type will contain employee name and age information:
Public class CustomeEvetnArgs: EventArgs
{
String name = "";
Int age = 0;
Public CustomeEvetnArgs ()
{}
Public string Name
{
Get {return this. name ;}
Set {this. name = value ;}
}
Public int Age
{
Get {return this. age ;}
Set {this. age = value ;}
}
}
Modify the definition of the delegate type DelegateClassHandle to include the necessary parameters:
Public delegate void DelegateClassHandle (object sender, CustomeEvetnArgs e );
The employee class code is modified as follows:
Public class Employee
{
Private string _ name;
Public string Name
{
Get {return _ name ;}
Set {_ name = value ;}
}
Private int _ age;
Public int Age
{
Get {return _ age ;}
Set {_ age = value ;}
}
Public event DelegateClassHandle PlayGame;
Public void Games ()
{
If (PlayGame! = Null)
{
CustomeEvetnArgs e = new CustomeEvetnArgs ();
E. Name = this. _ name;
E. Age = this. _ age;
PlayGame (this, e );
}
}
}
In the Games method, create a CustomeEventArgs object, and set the required attributes Name and Age.
The Chairman's notice method must also be modified accordingly:
Public class Admin
{
Public void Policy (object sender, CustomeEvetnArgs e)
{
System. Console. WriteLine (e. Name + "is" + e. Age. ToString ());
}
}
The code for associating two types of objects also needs to be modified accordingly:
Employee employee = new Employee ();
Employee. Name = "Mike ";
Employee. Age = 25;
Admin admin = new Admin ();
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Employee. Games ();
The modified code runs as follows,
When Mike calls the Games method to play a game, the PlayGame event is automatically triggered,
The event carries relevant information to notify admin,
The latter's Notify y method will receive the data and output "Mike is 25", telling the Chairman that Mike is 25 years old and is playing games during work hours.
A delegate can be a multi-channel broadcast (Mulitcast), that is, an event can be delegated to multiple objects for receiving and processing.
In the above example, if another manager has the same hobby as the chairman of the board,
The delegate object can also notify the employee of the PlayGame event.
First, define the manager class:
Public class Manager
{
Public void Policy (object sender, CustomeEvetnArgs e)
{
System. Console. WriteLine (sender. ToString () + "-" + e. Name );
}
}
The Notify method of the Manager type is the same as that of the Admin type, and the corresponding information is also received.
The bind method of the delegate multicast is still using the + = Operator. The method is shown in the following code:
Employee employee = new Employee ();
Employee. Name = "Mike ";
Employee. Age = 25;
Admin admin = new Admin ();
Manager manager = new Manager ();
Employee. PlayGame + = new DelegateClassHandle (admin. Policy );
Employee. PlayGame + = new DelegateClassHandle (manager. Policy );
Employee. Games ();
When this method is executed, the reader will see that the Notify y method of admin and manager will be notified and called for execution.
In this way, both the Chairman and manager will know that Mike is playing the game.
If the Chairman does not want the manager to receive this notification, how can he unbind PlayGame from the manager event?
It is also very simple. Run the following statement before the employee. Games method is called:
Employee. PlayGame-= new DelegateClassHandle (manager. Policy );
Finally, remind readers of the following,
The Games method in the Employee class must determine whether the event is null before triggering the event PlayGame.
After the Games method of the employee object triggers the event PlayGame,
A target function must be provided to handle this event, and the statement determines whether the target function exists.
If you remove this judgment and do not bind any event, you can directly call the Games method,
The program will bring up an NullReferenceException at the event PlayGame.
Can the reader draw any conclusions from the delegate and Event code?
There are two types that need to have a call relationship, but no actual call code is written in their respective implementations,
They only complete the message transmission process through an event and a third-party delegate type.
There is no close coupling between two types,
They seem to communicate loosely through a delegate object,
The "high aggregation" and "low coupling" ideas that have been promoted all the time have been realized.