Delegate and event (1), delegate event

Source: Internet
Author: User
Tags switch case

Delegate and event (1), delegate event
I personally think that the most important essence of c # is its delegation.

To be honest, it is now the era of c #5.0, and c #6 will soon come out. As a c #1 delegate, it has long been encapsulated by more advanced tools such as generic delegation and lambda expressions. Basically, few people declare a delegate in the program. However, it is also good to understand the basics,

Basic Concepts

A delegate is a special class (sealed class) and can be considered as a function pointer, which representsClass IThe method is the same as the input/output variable type and number of the delegated signature. The delegate itself can be passed in as a variable.

Using the classic greetPeople example, a similar situation is always encountered in actual work, that is, different results are executed for different inputs through the switch. However, we can see that the method executed by each switch is very similar, and the signature of the method is still identical. In this case, it is easy to think that when we add a new switch case, we need to add a new method and modify the existing GreetPeople method, this violates the principle of opening/closing (Closing modification ). Is there a way to extend the program without modifying the GreetPeople method?

Public class Program {public static void Main () {GreetPeople ("Alex", "Chinese"); GreetPeople ("Beta", "English"); GreetPeople ("Clara ", "France"); Console. readKey ();} public static void GreetPeople (string name, string lang) {switch (lang) {case "English": EnglishGreeting (name); break; case "Chinese ": chineseGreeting (name); break; case "France": FrenchGreeting (name); break ;}} public static void EnglishGreeting (string name) {Console. writeLine ("Morning," + name);} public static void ChineseGreeting (string name) {Console. writeLine ("good morning," + name);} public static void FrenchGreeting (string name) {Console. writeLine ("Bonjour," + name );}}

First, we should give up using the switch, otherwise we will not be able to avoid the fate of modifying the GreetPeople method. Then, we naturally think that, assuming that the second variable we input in the main function is not a string but a method name, we do not need the switch. Because we will directly go to the corresponding method and do not need to switch and then dispatch it. How can this problem be implemented? What does the input method name mean? The signatures of these methods are all the same. Can I use some method?Encapsulate them.?

As a result, the delegation emerged, which can solve all our problems above. A delegate represents a class of methods with the same signature and can be transformed into any of them. The delegate can also be used as a variable to pass in the method. Its behavior is the same as that of other types such as int and string. Many people think that delegation is hard to understand because delegation represents methods, while common types represent values or objects. For example, a string can represent any string, and an int can also represent any integer in a value range. A delegate represents a type of method (depending on its definition). When one of the variables of a function is a delegate, this means that we will pass in a method name that can be represented by the delegate.Delegate is a pointer to a method, You can point to different methods. For example, a string can point to a string on the stack, and an int can point to an integer on the stack.

Public class Program {// now this delegate represents a type of input string, without the output method public delegate void GreetPeopleDelegate (string name); public static void Main () {// different results will be obtained when different methods are passed in using the delegate ("Alex", ChineseGreeting); GreetPeople ("Beta", EnglishGreeting); GreetPeople ("Clara ", frenchGreeting); Console. readKey () ;}// the delegate can be used as a method variable to replace switch public static void GreetPeople (string name, GreetPeopleDelegate aGreetPeopleDelegate) {aGreetPeopleDelegate (name );} public static void EnglishGreeting (string name) {Console. writeLine ("Morning," + name);} public static void ChineseGreeting (string name) {Console. writeLine ("good morning," + name);} public static void FrenchGreeting (string name) {Console. writeLine ("Bonjour," + name );}}

 

 

Delegate methods and attributes

1. MulticastDelegate (delegate your own sealing class)

The lower-case delegate is the keyword you use to declare the delegate. After you declare it, the compiler creates a new seal class. The type of this class is MulticastDelegate (Inherited from System. MultipleDelegate, and then from System. Delegate) This is the difference between the delegate keyword of uppercase and lowercase d.

The new sealing class defines three methods: invoke, begininvoke, and endinvoke. Invoke is executed implicitly when you call the method represented by the delegate. For example, aGreetPeopleDelegate (name) is actually no different from aGreetPeopleDelegate. Invoke (name. Therefore, the method signature of Invoke is always the same as that of the Delegate. That is, if the delegate signature is int a (int x, int y), The invoke signature must be public int Invoke (int x, int y ).

The latter two give the delegate asynchronous capability. These two methods are put into the multi-threaded series for analysis.

2. System. MultipleDelegate and delegate call list (method chain)

The important method GetInvocationList () in System. MultipleDelegate obtains information about the methods represented by the current delegate. Note that this method returns an array, which means that the delegate can represent multiple methods at the same time (in this case, the invoke delegate will execute the group of Methods One by one ), this is also called delegated multi-channel broadcast. Through + = and-=, we can add and reduce methods for delegation. We do not need to study how the method chain is implemented, but we need to know the following:

1. You can add the same method again. At this time, this method will be executed twice.

2. You can delete all methods of the Delegate. That is, the Delegate does not represent a method for the time being. At this time, the invoke delegate will do nothing.

3. Even if you accidentally delete a method once, no exception will occur (for example, if you add a method and delete it twice by mistake). At this time, the Delegate does not represent any method at the moment.

4. + = and-= are the heavy loads of operators. In essence, they call the Combine and Remove methods in System. Delegate.

System. MultipleDelegate also loads = and! =, To determine whether two delegates are equal depends only on whether they represent the same method chain (that is, all the same methods pointing to the same object ).

3. System. Delegate

System. Delegate has two important public members: target and method. Method indicates the information of the Method. If method indicates a static member, Target is null. Otherwise, target indicates the object where the Method is located. Through GetInvocationList (), we can view the information of the method chain in the current delegate. In addition, this class also has the Combine and Remove methods, which have been overloaded by the quilt class, so they do not need to be called directly.

Public class Program {public delegate void GreetPeopleDelegate (string name); public static void Main () {// The instantiation delegate must be assigned a qualified method GreetPeopleDelegate aGreetPeopleDelegate = new GreetPeopleDelegate (ChineseGreeting); PrintInvocationList (aGreetPeopleDelegate. getInvocationList (); // Add a method named aGreetPeopleDelegate + = EnglishGreeting; PrintInvocationList (aGreetPeopleDelegate. getInvocationList (); anotherClass a = new anotherClass (); // Add a non-static method aGreetPeopleDelegate + =. nonStaticGreeting; PrintInvocationList (aGreetPeopleDelegate. getInvocationList (); Console. readKey () ;}// view the method chain represented in the current Delegate public static void PrintInvocationList (Delegate [] aList) {foreach (var delegateMethod in aList) {// Method indicates the details of the currently maintained Method. // If Method indicates a static member, Target is null. Otherwise, target indicates the Console of the object where the Method is located. writeLine (string. format ("Method name: {0}, value: {1}", delegateMethod. method, delegateMethod. target);} Console. writeLine ("----------------------------------");} public static void EnglishGreeting (string name) {Console. writeLine ("Morning," + name);} public static void ChineseGreeting (string name) {Console. writeLine ("good morning," + name);} public static void FrenchGreeting (string name) {Console. writeLine ("Bonjour," + name) ;}} public class anotherClass {public void NonStaticGreeting (string name) {Console. writeLine ("Bonjour," + name );}}

Dynamically maintain the delegate call list

As mentioned above, the delegate has a call list. We can operate on it dynamically to add or delete members for it. If we create a public delegate member list, we can easily implement multi-channel broadcast. The following example is from proficient c #6. Call list

public CarEngineHandler methodList;

Is public, and the external method main will create a new instance as the subscriber, in the appropriate circumstances, call the delegate and then execute the method in the delegate list.

Public class Program {public static void Main () {// creates a new subscriber var c = new Car ("Mycar", 0,100); // This Subscriber (consumer) subscribed to method OnCarEvent1 c. methodList + = OnCarEvent1; // cancel the annotation to implement multi-channel broadcast. At this time, two methods are executed. // c. methodList + = OnCarEvent2; for (int I = 0; I <10; I ++) {c. accel (20);} Console. readKey ();} public static void OnCarEvent1 (string msg) {Console. writeLine ("****** message from car ******"); Console. writeLine ("=" + MS G); Console. writeLine ("****************************");} public static void OnCarEvent2 (string msg) {Console. writeLine ("=>" + msg. toUpper () ;}} public class Car {public string name {get; set;} public int currentSpeed {get; set;} public int MaxSpeed {get; set ;} private bool isDead {get; set;} public delegate void CarEngineHandler (string message); public CarEngineHandler methodList; pub Lic Car (string name, int currentSpeed, int MaxSpeed) {this. name = name; this. currentSpeed = currentSpeed; this. maxSpeed = MaxSpeed; this. isDead = false;} public void Accel (int delta) {// method if (isDead) {if (methodList! = Null) methodList ("Sorry, car is broken");} else {currentSpeed + = delta; if (currentSpeed> = MaxSpeed) isDead = true; else Console. writeLine ("Current speed:" + currentSpeed );}}}

From delegate to event

One problem with the delegation in the previous example is that it is not safe enough. The caller canDirect AccessThe delegate object CarEngineHandler, and the list of calls to it:

1 invoke, that is, the delegate can be used at any time

2 + = or-=, or even direct value assignment (= ).

Sometimes, we do not want users to change the delegate members. In addition, we want the delegate not to be Invoke by the user, but to be called by the subscriber entrusted at a specific time. In other words, we hope that the following two codes will not be compiled:

// Assign a new object to the Delegate (we do not want other code to change the delegate direction) c. methodList = OnCarEvent1; // directly call the delegate (we do not want other code to be called directly, unless permitted) c. methodList. invoke ("test ");

At this point, the idea is to define the delegate itself as private, but in this case, all external classes cannot use the delegate. Therefore, we need to develop several public methods as a bridge for external classes to use internal private delegation. In the following code, methodList is private, so we cannot directly operate on it. We need to operate on it through two public methods of the Car class. (Unrelated code is omitted)

Public class Program {public static void Main () {// creates a new subscriber var c = new Car ("Mycar", 0,100 );
C. addmethod (OnCarEvent1); c. invoke ("test");} public class Car {public delegate void CarEngineHandler (string message); private CarEngineHandler methodList; public CarEngineHandler Addmethod (CarEngineHandler aMethod) {methodList + = aMethod; return methodList;} public void Invoke (string msg) {methodList. invoke (msg );}}

But the problem arises. If we want to pursue security for all the delegates, wouldn't we have to deal with these methods, and there are still many methods, such as adding methods and deleting methods, synchronous and asynchronous call of methods. This seems very troublesome and requires a lot of code. I believe that at this time you have also thought that another powerful thing is coming to play. It can solve all the problems above, and it is an event.

Related Article

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.