We are familiar with the concept of delegation, but in the use of a lot of people are still unable to control it, we can imagine, in peacetime coding, you are directly according to business logic directly create classes, New an object to operate or useful to delegate to do some of the functions more efficiently. The next blogger from the most obvious place to start, the middle insert for the commissioning of the source of the analysis of the gradual deepening of consolidation, simply speaking, is through examples, concepts, Source code to finally through the explanation of this article can let me and read your understanding of the delegation to improve some. Topics are roughly divided into:
- Understanding the concept of delegates through an example
- Callback for Delegate
- In-depth delegation (delegate chain-merge Delete delegate)
- Source code Analysis of the Entrustment
- Generic delegate
- Delegation of progress (syntactic sugar, covariance and contravariance, anonymous, closures)
- delegation chain, generic proxy source code analysis
- Delegate and reflection
- Asynchronous delegate
"One" through an example to understand the concept of delegation we have to learn to entrust, first of all to understand the concept of delegation, what is a delegate? How is a delegate defined in C #? These basic knowledge after understanding we are in depth to understand it, in C #, a delegate is a type, is a reference type, the delegate's keyword is
Delegate, the definition of a delegate is the same as the definition of a class, so where a class can be defined can also be defined as a delegate, public delegate void MyDelegate (); This defines a delegate type without a return value and no argument, so let's write a piece of code by delegating: Example 1: Basic composition of a delegate
1 class Program 2 {3 public delegate void MyDelegate (); 4 static void Main (string[] args) 5 {6 Mydelegat E mymessage = new MyDelegate (MyMethod); 7 mymessage (); 8 console.readline (); 9 }10 public static void MyMethod () one { Console.WriteLine ("I was called through a delegate"); }14}
The above code can be run directly, in the above code, first we declare a delegate MyDelegate, it is no return value, no parameters, and we also created a method MyMethod () , this method also has no return value, no parameters. So next we're going to look at the main function, in the main function, we create a delegate object mymessage (The delegate is a type, a reference type), and then at new we can look at what it calls "parameters". :
We can see that when creating an MyDelegate object, it is required to pass in a
void () TargetThis means no argument, no return value.
a target function(This we will use later, it means more than that), and finally we call this delegate object (for details, see the following source parsing). "Two" delegate callback static method and instance method delegate callback static method and instance method difference: in instance 1, we give the delegate a static method, In this way, simply say the difference between static and instance methods "static methods are defined by the keyword static, and the static method does not require an instance to access the object through the class name." Non-static members in a class cannot be accessed directly in a static method. An instance method is called by a specific instance object, and can be accessed by any member of the instance object.
1 public delegate void Mypersondelegate (string name); 2 static void Main (string[] args) 3 {4 mypersondelegate persondelegate = new Mypersondelegate (person.getpersonname); 5 persondelegate ("Static"); 6 mypersondelegate personintancedelegate = new Mypersondelegate (new Personintance (). Getpersonname); 7 personintancedelegate ("intance"); 8} 9 class Person10 {One public static void Getpersonname (String age) { Console.WriteLine (age); }15}16 class PersonIntance17 {public void Getpersonname (string name) { Console.WriteLine (name) ; }22}
In the above code, first we define a delegate Mypersondelegate, which is no return value, and requires a string type parameter type (in this case, the delegate can be covariant and contravariant, for specific reference.) NET variability resolution (covariance and Contravariance), and then we define two classes of person and personinstance , each of whom declares a Getpersonnam static method, thePersonintance class declares a Getpersonname instance method, in main function main, we make separate calls. At the time of execution, We will find the instance of the delegate followed by a parameter, which is actually the parameter of the method, because the delegate that we define requires a method that executes a non-return value, has a parameter of type string , when executing the delegate, I deliberately write an invoke () This method, the main here is to be familiar with the invoke, because the next will be related to some of its knowledge points, Invoke is also a method of invoking the delegate is the same as directly through the delegate instance execution is the same. What happens inside the delegate for the callback static method and the callback instance method? We can view it through the source parsing method (described in the following paragraph).
"Three" delegate in depth (delegate chain-merge Delete delegate)
Before discussing the delegation chain, let's familiarize ourselves with the merging and deletion of delegates (which may be better understood), there are two static methods under the delegate type combine and remove (the next source parsing will be explained), Combine is responsible for connecting the invocation list of two delegate instances together, and remove is responsible for removing the invocation list of another instance from one of the delegate instances, following an example to show the merging and deletion of delegates
Example 3: Consolidation and deletion of Delegates (Combine,remove)
Mypersondelegate persondelegate = new Mypersondelegate (person.getpersonname); Delegate instance 1MyPersonDelegate personintancedelegate = new Mypersondelegate (new Personintance (). Getpersonname); Delegate instance 2var dele = (mypersondelegate) delegate.combine (persondelegate, personintancedelegate); By combine merging two delegate instances, a new delegate instance Dele is obtained. Invoke ("Albin"); After the output is merged, the delegate instance Console.ReadLine ();
In the above code, we first define the instance of two delegates personintancedelegate, Personintancedelegate The next segment code we see Delegate.combine (), merges the two delegate instances together and outputs the result:
This is to combine two delegates for a delegate, and we're not looking at a simpler way of writing.
var dele = (mypersondelegate) delegate.combine (persondelegate, personintancedelegate); var dele = persondelegate + = Personintancedelegate;dele. Invoke ("Albin");
We will change the way combine to + = effect and combine is the same. (The following will have source parsing), familiar with the event, we can find that this is the event load is the same.
Deletion of Delegates
In the above we introduce the merger of the delegate, then there will be a merge delete, in the delegate there is a static method remove, which is used to remove the merged delegate, it requires a parameter of Delegate.remove (Source,value); This indicates a list of calls that require a delegate, and a call list that provides a delegate to remove the source:
Example 3: The delegate's remove
var deleremove = (mypersondelegate) delegate.remove (Personintancedelegate,dele); Deleremove.invoke ("Albin");
Through the previous combine, this code is not difficult to understand, here is not much to say, followed by its simple wording
var deleremove = personintancedelegate-= dele; Deleremove.invoke ("ALbin");
The last two output values are personintancedelegate values.
"Four" delegated source code parsing (anti-compilation view delegate callback static and the difference between the instance, and the nature of the delegation chain)
Next we refer to the previous delegate callback and the delegate chain to decompile, to see how the delegate at the time of invocation of the implementation of the internal, first posted part of the source of the delegation:
Delegate part source code
In the above source code, we see that delegate has four private fields, namely:object _target;object _methodbase;intptr _methodptr;intptr _methodptraux;
_target: Returns a reference type, which is the method used to represent the reference (callback) if the static method _target returns NULL, if the callback is an instance object then returns the reference address of the method, looking down at the property of a target, this property corresponds to _ Target This field, in addition target returns the This.gettarget (), by commenting "The object on which the current delegate invokes the instance method, if th E delegate represents an instance method; Null if the delegate represents a static method. "also confirms the role of _target.
Internal Virtual Object Gettarget () { if (!this._methodptraux.isnull ()) { return null; } return this._target;}
After we look at this property of Gettarget, we find that there is a field _methodptraux, and we are looking at MethodInfo Getmethodimpl () This method is described as: the Caller does not has access to the method represented by the delegate (for example, if the method is private). if the delegate points to an instance method, then _methodptraux is 0, and if the delegate points to a static method, then the _methodptraux function is the same as _mthodptr when the delegate points to the instance method.
_methodptr is a pointer to the method.
_methodbase is the method that is passed when assigning a value to a delegate
"Five" generic delegate
Generic delegates are mainly for us to solve the number of defined delegates, after the. NET freamwork Support Generics, we can define the delegate in a generic way, one of the benefits of generics first is to reduce complexity and improve reusability (refer to For more details). NET generic parsing (above)), let's look at the charms of generic delegates by example.
Example 4: Action of a generic delegate
Action instance action<string> action = new action<string> (person.getpersonname); Action. Invoke ("Albin"); Console.ReadLine ();
In the code above, we created a generic delegate action, and when we created it we could see that action<> it required a parameter type for a delegate, and when we created the instance, we asked for a void (string) Target, just like we did in instance 1. There is no return value, there is one argument. Also the parameter type is specified for in, which indicates that it is reversible (. NET variability analysis (covariance and contravariance));
. NET Freamwork provides us with 17 action delegates, ranging from parameterless to up to 16 parameters, which is enough for us (unless your delegate is going to pass more than 16 arguments, then you define it yourself), and note that: The action gives us a delegate that has only parameters and no return value, so what if we are going to pass with the return value and arguments? At this point,. NET Freamwork also takes this into account, and it provides us with another function, Func, that provides 17 parameters plus a return value type as action, and when you first use them, it feels like the sky is blue all the time ... It's so handsome.
Let's take a look at the Func function by an example
Example 5: Func of a generic delegate
Func instance func<string, string> func = new func<string, string> (person.getname); var result = Func. Invoke ("This is Arg"); Console.WriteLine (result); Console.ReadLine (); class person{public static string GetName (string name) { return name; }}
In the code above, we create an instance of Func, requiring that the method to be called by Func has a string-type return value, and has a string-type argument, so we define a getname method in the person class, in Func. Invoke (""), when called, returns the type of the value returned by GetName. The final output is:
Benefits of Generic delegates:
In the normal development process, we should try to use the generic delegate way to use the delegate, avoid using the custom delegate
First: We can reduce the number of definitions we entrust
Second: Generics are type-safe
Third: Convenient for covariance and contravariance
IV: Simplifying the Code
Progress of the "six" delegates (syntactic sugar, covariance and contravariance, anonymous, closures)
C # syntax Sugar: The so-called syntactic sugar is in C # code, simplifying the amount of code, is the code written more graceful, so called syntax sugar.
Anonymous functions: Anonymous functions introduced in c#2.0, so-called anonymous functions are instances of delegates without actual method declarations, which are directly embedded in the code
Lambda: A lambda expression introduced in c#3.0, which is more concise than an anonymous method
It's not too deep to describe lambda and anonymity, because in a few days it will be written about. NET parsing of lambda and anonymous internal mechanism implementations. Here we just need to know.
Example 6: The Anonymous method class simplifies the code of the delegate through lambda.
Mypersondelegate persondelegate = P = Console.WriteLine (p.tostring ());p Ersondelegate.invoke ("No return value, parameter"); MyDelegate mydelegate = () = Console.WriteLine ("No parameter, no return value"); MyDelegate (); Mypersondelegatestr Delegatestr = p = + {return p;}; Console.WriteLine (Delegatestr.invoke ("with parameters, return value")); Console.ReadLine ();
Example 7: implementation via closures
var f = Func (); Console.WriteLine (f ()); Console.ReadLine ();
public static func<int> Func () { var i = ten; return () = { return i; }; }
The above code we can decompile to look at:
It can be seen that the return returned is an anonymous delegate, because Func it is required to have a return value from which to return an anonymous delegate object, in the anonymous delegate, I added a Console.WriteLine (i); In the instance of the code is not, this is mainly because it can reflect a method body, if according to our example of the compiler to decompile it directly is return () = i; The closure itself is not easy to understand, this can be specifically to come up with an article to explain it. Don't dig into it here.
"Seven" entrust chain, generic source code Analysis
Delegation chain/Multicast Delegate/merge Delete delegate source code parsing
[__dynamicallyinvokable, Targetedpatchingoptout ("performance critical to inline across NGen image boundaries")] public static Delegate Combine (Delegate A, Delegate b) { if (a = = null) { return b; } return A.combineimpl (b); }
The above code is the internal implementation of combine, we can see that A is null refers to an empty method instance, directly return another delegate object, through Combineimpl to concatenate two delegate invocation list
Delete Delegate
<summary>removes the last occurrence of the invocation list of a delegate from the invocation list of another de legate.</summary>//<returns>a new delegate with a invocation list formed by taking the invocation L ist of <paramref name= "source"/> and removing the last occurrence of the invocation list of <paramref name= "Valu E "/>, if the invocation list of <paramref name=" value "/> is found within the invocation list of <paramref NA Me= "source"/>. Returns <paramref name= "source"/> If <paramref name= "value"/> is null or if the invocation list of <param Ref name= "Value"/> is not found within the invocation list of <paramref name= "source"/>. Returns a null reference if the invocation list of <paramref name= "value"/> is equal to the invocation list of < Paramref name= "source"/> or if <paramref name= "source"/> is a null reference.</returns>//<PA Ram name= "source" >the deLegate from which to remove the invocation list of <paramref name= "value"/>. </param>//<param name= "value" >the delegate that supplies the invocation list to remove from the INVO cation list of <paramref name= "source"/>. </param>//<exception cref= "t:system.memberaccessexception" >the caller does not having access to the ME Thod represented by the delegate (for example, if the method is private). </exception>//<exception cref= "T:System.ArgumentException" >the delegate types do not match.</exce ption>///<filterpriority>1</filterpriority> [__dynamicallyinvokable, SecuritySafeCritical] public static Delegate Remove (Delegate source, Delegate value) {if (source = = null) { return null; } if (value = = null) {return source; } if (! Delegate.internalequaltypes (Source, ValUE) {throw new ArgumentException (environment.getresourcestring ("Arg_dlgttypemis")); } return source. Removeimpl (value); }
The code above is the internal implementation of remove, which removes the last matching item from the invocation list of the delegate from another delegate, and is removed by the Removeimpl method, implemented internally by the Removeimpl method:
<summary>removes the invocation list of a delegate from the invocation list of another delegate.</summary> <returns>a new delegate with a invocation list formed by taking the invocation list of the current delegate and Removing the invocation list of <paramref name= "value"/>, if the invocation list of <paramref name= "value"/> ; is found within, the current delegate ' s invocation list. Returns the current delegate if <paramref name= "value"/> is null or if the invocation list of <paramref name= "va Lue "/> is not a found within the current delegate ' s invocation list. Returns NULL if the invocation list of <paramref name= "value"/> is equal to the current delegate ' s invocation list. </returns>///<param name= "D" >the delegate that supplies the invocation list-to-remove from the invocation Lis T of the current delegate. </param>///<exception cref= "t:system.memberaccessexception" >the caller does not having access to theMethod represented by the delegate (for example, if the method is private). </exception>protected virtual Delegate Removeimpl (Delegate D) {if (!d.equals (this)) {return this; } return null;
. NET delegate parsing