[C # Basic Knowledge series] Topic 3: How to Use delegation to package multiple methods-delegation chain

Source: Internet
Author: User

Introduction:

The previous topic introduced how compilers translate delegation, and looked at delegation from the perspective of intermediate language, hoping to help you further understand delegation, however, in the previous sections, the delegate only encapsulates one method. Can the delegate encapsulate multiple methods? Because I often hear such things in my life, such as my opinions on behalf of everyone. Since delegation is also a representative, if he can only represent one person, then his charm will not be great, so can we delegate multiple methods? The answer is yes. This is what we will talk about in this topic-delegated chain,The delegation chain is also a delegation, just because it is a combination of multiple delegation chains, so we call it the same as the delegation chain..

 

I. What is a delegated chain?

We usually bind a method when instantiating a delegate object. The delegate introduced in the previous topic also encapsulates a method. In the preceding example, only one person is appointed as a delegate, that is to say, there is only one client, but this is obviously not the case in real life. In the case of a lawsuit, a lawyer can answer multiple cases at the same time and receive the appointment of multiple persons at the time. In this way, the lawyer is bound to multiple clients and needs to know the cases of multiple clients. In fact, this is the delegate chain in life. At this time, this lawyer is not just a representative of a lawyer, but a lawyer of multiple clients. In my life, the delegated chain is similar to the delegated chain in C #. Now let's talk about what the delegated chain in C # is?

FirstThe delegated chain isOneDelegateTherefore, you do not need to see the new features in C #. However, to link Multiple delegate chains together, you must store references of multiple delegates, where does the delegate link object store references of multiple delegates? Do you still remember that in the previous topic, we introduced three non-public fields for the delegate type? The three fields are -- _ target, methodptr, and _ invocationlist. You can refer to my previous topic article as to what these fields represent. HoweverThe _ invocationlist field stores multiple delegate references..

To better explain how invocationlist stores delegate references, Let's first look at the example and running result of a delegate chain and then analyze the cause:

Using system; namespace delegatetest {public class program {// declare a delegate type, and its instance references a method // This method returns an int parameter, return void Type Public Delegate void delegatetest (INT parm); public static void main (string [] ARGs) {// instantiate delegate delegatetest dtstatic = new delegatetest (program. method1); // use the instance method to instantiate the delegate delegatetest dtinstance = new delegatetest (new program (). method2); // call the delegate dtstatic (1) implicitly; // call the invoke method explicitly to call the delegate dtinstance. invoke (1); // implicitly call the delegate dtstatic (2); // explicitly call the invoke method to call the delegate dtinstance. invoke (2); console. read ();} Private Static void Method1 (INT parm) {console. writeline ("static method called, parameter value:" + parm);} private void method2 (INT parm) {console. writeline ("instance method called, parameter value:" + parm );}}}

Running result:

Next we will analyze why such a result appears:

At the beginning, we instantiated two delegate variables, as shown in the following code:

// Use the static method to instantiate the delegate delegatetest dtstatic = new delegatetest (program. method1); // use the instance method to instantiate the delegate delegatetest dtinstance = new delegatetest (new program (). method2 );

The initial status of the delegate object referenced by the delegate variables dtstatic and dtinstance is as follows:

Then we define a reference variable for the delegate type.Delegatechain,At the beginning, it does not have any delegate object, and is a null reference,When we execute the following line of code,

delegatechain = (DelegateTest)Delegate.Combine(delegatechain, dtstatic);

CombineThe method found that the objects to be merged are null and dtstatic. Internally, combine directly returns the objects in dtstatic. At this time, the delegatechain and dtstatic variables reference the same delegate object, as shown in:

To demonstrate the delegate chain, we add another delegate through code, and then callCombineThe Code is as follows:

 delegatechain = (DelegateTest)Delegate.Combine(delegatechain, dtinstance);

At this time,The combine method finds that delegatechain has referenced a delegate object (the delegate object referenced by destatic has been referenced), SoCombineYesConstruct a new delegate object(This is very string. concat, our simple use is to connect two strings through the + operator. For discussion about strings, you can refer to this article http://www.cnblogs.com/zhili/archive/2012/06/25/String_StringBuilder.html in my blog ), this new delegate object initializes its private fields _ target and _ methodptr,Then, the _ invocationlist field is initialized as an array that references a delegate object. The first element of this array (subscript: 0) is initialized as a delegate that references the wrapped Method1 method, the two elements of the array are initialized as the delegate (that is, the delegate object referenced by dtinstance) that references the method2 method. Finally, the delegaechain is set to reference the new delegate object.The following figure shows the delegation chain (also called multicast delegation ):

In the same way, if you add the third delegate to the delegate chain, the process is the same as above. At this time, a new delegate object will be created, in this case, the _ invocationlist field will be initialized to reference an array that stores the three delegate objects, however, someone may ask -- A new delegate object will be created after the combine method is called for the delegate type variable that has referenced the delegate object, then re-initialize the three fields of the new delegate object, finally, we will reference the previous delegate type variable to the newly created delegate object (here we will help you summarize the process of creating the delegate chain). What should we do with the previous delegate object? I believe most people will have this question, which is very similar to the Concat method of the string. The previous delegate object and the array referenced by the -- invocationlist field will be reclaimed (exactly because of this, the delegate is the same as the string ).

Note:: We can also call the Remove Method of delegate to delete the delegate from the chain, for example, when calling the following code:

 delegatechain =(DelegateTest)Delegate.Remove(delegatechain,new DelegateTest(method1));

When the remove method is called, It scans the internal maintenance of the delegate object referenced by delegatechain (the first parameter)Delegate Array(If the delegate array is empty, calling the remove method will not be helpful, that is, it will not delete any delegate references. Here, the scan mainly indicates that scanning is performed from the delegate array ), if the _ target and _ methodptr fields of the delegate object referenced by delegatechain are found

The delegate that matches the field in the second parameter (new delegate). If only one data item is left in the array after deletion, return the data item (instead of creating a new delegate object and then initializing it, the _ invocationlist is null instead of saving an array referenced by the delegate object, specifically, you can remove one and debug it). If there are still multiple data items in the array, create a new delegate object -- create and initialize the _ invocationlist array (at this time, the delegate object referenced by the array is missing because it is deleted using the Remove Method), and,Each call to remove a method can only delete one delegate from the chain, rather than deleting all the delegates with matched _ target and _ methodptr fields (this can be viewed by debugging)

 

Ii. How to control the delegated call in the delegated chain

I believe you can understand how to create a delegate link object. However, from the running results, we can also see that each method encapsulated by the delegate link is executed in sequence each time the delegate link is called, if an exception is thrown for the called delegate in the delegate chain, all subsequent objects in the chain cannot be called, and if the delegate has a non-void return type, only the last return value will be retained, and the return values of all other callback methods will be discarded. Does this mean that the return values of all other operations will never be seen? This is not the case. We can callDelegate. getinvocationlistMethod To explicitly call each delegate in the chain, and you can add some custom output.

GetinvocationlistReturns an array composed of delegate references. Each array points to a delegate object in the chain. Internally,GetinvocationlistCreate and initialize an array so that each element of the data references a delegate in the chain, and then return a reference to the array. If_ InvocatinlistThe field is null. The returned array has only one element, which is the delegate instance itself. The following is a program to demonstrate:

Namespace delegatechaindemo {class program {// declare a delegate type. Its instance references a method // This method returns an int parameter and void Type Public Delegate string delegatetest (); static void main (string [] ARGs) {// use a static method to instantiate the delegate delegatetest dtstatic = new delegatetest (program. method1); // use the instance method to instantiate the delegate delegatetest dtinstance = new delegatetest (new program (). method2); delegatetest dtinstance2 = new delegatetest (new program (). method3); // defines a delegate chain object. The Initialization is null at the beginning, that is, it does not represent any method (I am, I don't represent anyone) delegatetest delegatechain = NULL; delegatechain + = dtstatic; delegatechain + = dtinstance; delegatechain + = dtinstance2; // delegatechain = (delegatetest) delegate. remove (delegatechain, new delegatetest (Method1); // delegatechain = (delegatetest) delegate. remove (delegatechain, new delegatetest (new program (). method2); console. writeline (test (delegatechain); console. read ();} Private Static string Method1 () {return "this is the static method 1";} private string method2 () {Throw new exception ("an exception thrown ");} private string method3 () {return "this is instance method 3";} // test the call delegate method Private Static string test (delegatetest chain) {If (chain = NULL) {return NULL;} // use this variable to save the output string stringbuilder returnstring = new stringbuilder (); // obtain a delegate array, each element references the delegate [] delegatearray = chain in the chain. getinvocationlist (); // traverse each delegate in the array foreach (delegatetest t in delegatearray) {try {// call the delegate to obtain the returned value returnstring. append (T () + environment. newline);} catch (exception e) {returnstring. appendformat ("exception thrown from {0} method, exception information: {1} {2}", T. method. name, E. message, environment. newline) ;}/// return the result to the caller return returnstring. tostring ();}}}

Running result:

From the running results, we can obtain the return values of each callback method and add some custom return values (a line feed string is added to the program ), in this way, you can control each delegate object in the delegate chain. Even if one of them throws an exception, we can capture it without causing the problem that subsequent delegate objects cannot be called.

 

Iii. Summary

This topic describes how to create a delegated link and how to share the process of creating a delegated link in detail. The second part focuses on the limitations of delegated links, then, call the getinvocationlist method to return a delegate array, so that each delegate in the delegate array can be traversed to notify the delegate call process, in this way, more control can be performed on the call of the delegate chain. This topic has been introduced. I believe you will have a deeper understanding of the delegation through these three topics, then why do we need to write three topics to detail the delegation? It is mainly about the events, lambda expressions, and LINQ that will be introduced later. Therefore, a better understanding of delegation is a basis for subsequent features, I hope this will help you. I will introduce the event in the next topic.

Here, I hope you can support my it blog contest. My homepage is: Workshop.

 

 

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.