[Post]. Net delegate: a c # bedtime story

Source: Internet
Author: User
Original Author: Chris sells (www.sellsbrothers.com)

Yuan Xiaohui (www.farproc.com http://blog.csdn.net/uoyevoli)

Tight coupling

Once upon a time, in a strange land in the south, Peter was a worker, who was very diligent and always gave up his boss.
Baishun. However, his boss is a mean person. He never trusts others and insists that he be informed of his work progress at any time,
To prevent him from being lazy. But Peter didn't want his boss to stay in his office and stare at him.
Make a commitment: Whenever I make some progress in my work, I will let you know in time. Peter's pass cycle
Use "reference with type" (Original: "typed reference", that is, delegate ??) "Callback
"His boss came to fulfill his promise as follows:

Class worker {
Public void advise (boss) {_ boss = boss ;}
Public void dowork (){
Console. writeline ("Work: Start of work ");
If (_ boss! = NULL) _ boss. workstarted ();

Console. writeline ("Work: Work in Progress ");
If (_ boss! = NULL) _ boss. workprogressing ();

Console. writeline ("Work: finished "");
If (_ boss! = NULL ){
Int grade = _ boss. workcompleted ();
Console. writeline ("Worker's work score =" + grade );
}
}
Private boss _ boss;
}

Class boss {
Public void workstarted () {/* The boss does not care. */}
Public void workprogressing () {/* The boss does not care. */}
Public int workcompleted (){
Console. writeline ("Almost time !");
Return 2;/* Total score: 10 */
}
}

Class universe {
Static void main (){
Worker Peter = new worker ();
Boss = new boss ();
Peter. Advise (boss );
Peter. dowork ();

Console. writeline ("Main: worker finished ");
Console. Readline ();
}
}

Interface

Now, Peter has become a special person. He not only can tolerate stingy bosses, but also has a secret with the universe around him.
He thought that the universe was also interested in his work schedule. Unfortunately, he must also add
A special callback function, advise, is used to report the work progress to his boss and the universe at the same time. Peter wants
The notification list is separated from the implementation methods of these notifications, so he decided to separate the method into an interface:

Interface iworkerevents {
Void workstarted ();
Void workprogressing ();
Int workcompleted ();
}

Class worker {
Public void advise (iworkerevents events) {_ Events = events ;}
Public void dowork (){
Console. writeline ("Work: Start of work ");
If (_ events! = NULL) _ Events. workstarted ();

Console. writeline ("Work: Work in Progress ");
If (_ events! = NULL) _ Events. workprogressing ();

Console. writeline ("Work: finished "");
If (_ events! = NULL ){
Int grade = _ Events. workcompleted ();

Console. writeline ("Worker's work score =" + grade );
}
}
Private iworkerevents _ events;
}

Class BOSS: iworkerevents {
Public void workstarted () {/* The boss does not care. */}
Public void workprogressing () {/* The boss does not care. */}
Public int workcompleted (){
Console. writeline ("Almost time !");
Return 3;/* Total score: 10 */
}
}

Delegate

Unfortunately, Whenever Peter is busy communicating with his boss through the implementation of interfaces, there is no chance to notify the universe in time. To
He should ignore the reference from his boss in the distance, so that other objects that implement iworkerevents can get his work.
Report. ("At least he 'd been acted the reference of his boss far away from him
So that others who implemented the iworkerevents interface cocould be notified
Of his work progress)

His boss complained a lot. "Peter !" His boss shouted, "why did you get started at work?
Are you bothering me ?! I don't care about these events. Not only have you forced me to implement these methods, but you are still wasting my time
Handle your events during expensive work hours, especially when I go out! Can you leave me alone?
"

Peter realized that although the interface is useful in many cases, the "granularity" is not good enough when used as an event.
He wants to notify others only when they want them, so he decided to separate the interface methods into separate delegates.
Each delegate is like a small interface method:

Delegate void workstarted ();
Delegate void workprogressing ();
Delegate int workcompleted ();

Class worker {
Public void dowork (){
Console. writeline ("Work: Start of work ");
If (started! = NULL) started ();

Console. writeline ("Work: Work in Progress ");
If (progressing! = NULL) progressing ();

Console. writeline ("Work: finished "");
If (completed! = NULL ){
Int grade = completed ();
Console. writeline ("Worker's work score =" + grade );
}
}
Public workstarted started;
Public workprogressing progressing;
Public workcompleted completed;
}

Class boss {
Public int workcompleted (){
Console. writeline ("better ...");
Return 4;/* Total score: 10 */
}
}

Class universe {
Static void main (){
Worker Peter = new worker ();
Boss = new boss ();
Peter. Completed = new workcompleted (boss. workcompleted );
Peter. dowork ();

Console. writeline ("Main: worker finished ");
Console. Readline ();
}
}

Static listener

In this way, Peter will no longer bother his boss with what his boss doesn't want, but he hasn't put the universe in his surveillance.
Listener list. Because the universe is an entity that contains everything, it does not seem suitable for the use of instance methods (imagine
, Instantiate how much resources a "Universe" will spend .....), So Peter needs to be able to hook up the static delegate
The delegation supports this well:

Class universe {
Static void workerstartedwork (){
Console. writeline ("universe notices worker starting work ");
}

Static int workercompletedwork (){
Console. writeline ("universe pleased with worker's work ");
Return 7;
}

Static void main (){
Worker Peter = new worker ();
Boss = new boss ();
Peter. Completed = new workcompleted (boss. workcompleted );
Peter. Started = new workstarted (universe. workerstartedwork );
Peter. Completed = new workcompleted (universe. workercompletedwork );
Peter. dowork ();

Console. writeline ("Main: worker finished ");
Console. Readline ();
}
}

Event

Unfortunately, the universe is too busy to focus on its individual at any time. It can replace him with its own delegate.
The boss's Commission is required. This is an unconscious side effect of making Peter's worker class's delegate field public.
Similarly, if Peter's boss is impatient, he can decide to inspire Peter's delegation by himself.
Board ):

// Peter's boss taking matters into his own hands
If (Peter. completed! = NULL) Peter. Completed ();
Peter doesn't want this to happen. He realizes that he needs to provide "Registration" and "anti-Registration" functions for each delegate.
The listener can add and remove the delegate by themselves, but at the same time, it cannot empty the entire list and it cannot inspire Peter at will.
. Peter didn't implement these functions by himself. Instead, he used the event keyword to make C # compiler build for him.
These methods:

Class worker {
...
Public event workstarted started;
Public event workprogressing progressing;
Public event workcompleted completed;
}

Peter knows that the event keyword encapsulates a property outside the delegate and only allows the C # client to use the + = and-= operators.
To add and remove, forcing his boss and the universe to use the event correctly.

Static void main (){
Worker Peter = new worker ();
Boss = new boss ();
Peter. Completed + = new workcompleted (boss. workcompleted );
Peter. Started + = new workstarted (universe. workerstartedwork );
Peter. Completed + = new workcompleted (universe. workercompletedwork );
Peter. dowork ();

Console. writeline ("Main: worker finished ");
Console. Readline ();
}

"Harvest" all results

At this moment, Peter finally gave a sigh of relief. He successfully met the needs of all the listeners and avoided
Fixed Implementation of tight coupling. But he noticed that his boss and the universe scored points for its work, but he only received
One score. In the face of multiple listeners, he wants to "get" all the results, so he goes deep into the agent and polls
List of listeners, which can be manually called one by one:

Public void dowork (){
...
Console. writeline ("Work: finished "");
If (completed! = NULL ){
Foreach (workcompleted WC in completed. getinvocationlist ()){
Int grade = WC ();
Console. writeline ("Worker's work score =" + grade );
}
}
}

Asynchronous notification: inspire & forget

At the same time, his boss and the universe are still busy dealing with other things, that is to say, the things they spent scoring Peter have changed.
Very long:

Class boss {
Public int workcompleted (){
System. Threading. thread. Sleep (3000 );
Console. writeline ("better..."); return 6;/* Total score: 10 */
}
}

Class universe {
Static int workercompletedwork (){
System. Threading. thread. Sleep (4000 );
Console. writeline ("universe is pleased with worker's work ");
Return 7;
}
...
}
Unfortunately, Peter has to wait for the listener to rate himself every time he notifies him. Now these notifications have been too much for him.
. So he decided to forget the score and just asynchronously stimulate the event:

Public void dowork (){
...
Console. writeline ("Work: finished "");
If (completed! = NULL ){
Foreach (workcompleted WC in completed. getinvocationlist ())
{
WC. begininvoke (null, null );
}
}
}

Asynchronous notification: Round Robin

This allows Peter to notify his listener and immediately return to work so that the thread pool of the process can call these agents.
As time passes, Peter finds that he has lost his work feedback. He knows to listen to others' praise and work hard.
As important, he asynchronously fires events, but periodically polls to obtain available scores.

Public void dowork (){
...
Console. writeline ("Work: finished "");
If (completed! = NULL ){
Foreach (workcompleted WC in completed. getinvocationlist ()){
Iasyncresult res = WC. begininvoke (null, null );
While (! Res. iscompleted) system. Threading. thread. Sleep (1 );
Int grade = WC. endinvoke (RES );
Console. writeline ("Worker's work score =" + grade );
}
}
}

Asynchronous notification: Delegate

Unfortunately, Peter came back to a situation he wanted to avoid from the beginning. For example, the boss stood behind and stared at his work. Yu
Yes, he decided to use his delegate as the notification of the asynchronous delegate he called, so that he could return to work immediately,
However, you can still be notified after someone else scores his job:

Public void dowork (){
...
Console. writeline ("Work: finished "");
If (completed! = NULL ){
Foreach (workcompleted WC in completed. getinvocationlist ()){
WC. begininvoke (New asynccallback (workgraded), WC );
}
}
}

Private void workgraded (iasyncresult res ){
Workcompleted WC = (workcompleted) res. asyncstate;
Int grade = WC. endinvoke (RES );
Console. writeline ("Worker's work score =" + grade );
}

Happiness in the universe

Peter, his boss, and the universe finally met. Peter's boss and universe can receive notifications of events they are interested in.
To reduce the burden of implementation and non-essential travel expenses ". Peter can notify them, no matter how much they will spend
It can be returned from the target method for a long time, and its results can be obtained asynchronously. Peter knows that this is not * very *
This is simple, because when an event is asynchronously triggered, the method needs to be executed in another thread, and Peter's objective method completes
The same is true for notifications. However, Mike and Peter are good friends. He is very familiar with the thread.
Domain provides guidance.

They live happily forever ...... <End>
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.