650) this.width=650; "id=" Bloglogo "src=" Http://www.cnblogs.com/Skins/custom/images/logo.gif "alt=" Back to Home "/>
What is a delegate? First knowledge entrusted
in many applications (c,c++), it is necessary for an object to use some kind of callback mechanism to communicate with the entity that created it, and under the. NET platform, a callback function mechanism is provided through a delegate, and under the. NET platform, the delegate ensures that the callback function is type-safe (which is also the. Net The difference between freamwork and unmanaged code). Essentially, a delegate is a type-safe object that points to another method (or methods) that will be called later in the program, passing the method as a parameter.
Defining delegate types in C #
When you create a delegate type in C #, you need to use the keyword delegate keyword, which can be customized, but the delegate specifies the signature of a callback method.
1//Declares a delegate that can point to any incoming two int types and the return value of the method is int.2 public delegate int Binary (int x,int y); 3 4//declares a delegate, The delegate can point to any incoming string type and the method returns a value of VOID5 public delegate void Delegatebackcall (String str);
Delegate callback static method with delegate Send object status notification
Take a look at the code first:
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
void main () { program.main (); } public delegate void delegatebackcall (Int value); class Program { public static void main () { counter (1,4,null); counter (1,4,new Delegatebackcall (Staticdelegatetoconsole)); } private static void counter (Int x,int y,delegatebackcall foo) { for (var i = x;i <= y;i++) { &nbSp; if (foo != null) foo (i); 21 } } private static void staticdelegatetoconsole (Int num) { console.writeline ("Item : " + num); } }
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
first, define a delegate named Delegatebackcall, the method specified by the delegate to get the int type parameter, return void, define a private static method counter in the program class, to count the number of integers from x to Y, and at the same time, The counter method also gets a foo,foo that is a reference to a Delegatebackcall delegate object, and in the method body we first traverse it, if Foo is not NULL, Call the callback function specified by the Foo variable. Then the callback function passed in is the value of the data item being processed .
Then, in the main function of program, the first time you call counter, the third parameter passes NULL, and the callback function is not executed in the counter function.
Then the second call to the counter function, the third parameter is passed a new constructed Delegatebackcall delegate object (in fact, this delegate object is a wrapper of the method, so that the method can be indirectly through the wrapper callback), Then the static method Staticdelegatetoconsole is passed to the constructor of the DELEGATEBACKCLL delegate type (Staticdelegatetoconsole is the method to be wrapped), and when counter executes, The static method Staticdelegatetoconsole is called after each data item is traversed, and the result is the final output:
1 result:2 item:1 3 item:24 item:3 5 item:4
Invoking an instance method with a delegate using a delegate to send an object status notification
Let's start by looking at the main () function, where the third call counter, and put the code out here.
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
1 class program 2 { 3 public static void main () 4 { 5 counter (1,4,null); 6 counter (1,4,new delegatebackcall (staticdelegatetoconsole)); 7 8 counter (1,4,new delegatebackcall (new Program (). Instancedelegatetomessage)); 9 }10 private void instancedelegatetomessage (Int num) 11 {12 console.writeline ("message : " + num);13 }14 }
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
When the counter function is called the third time, the third argument passes the instance method created by program, which wraps a reference to the Instancedelegatetomessage method, which is an instance method. As with static calls, When counter calls the Foo callback, the Instancedelegatetomessage instance method is called, and the newly constructed object is passed as an implicit this parameter to the instance method.
The result of the final output is:
1 message:12 message:23 message:34 message:4
With the above two examples we know that a delegate can wrap a call to an instance method and a static method, and if it is an instance method, then the delegate needs to know which object instance the method operates on (the wrapper instance is useful, and the code inside the object can access the instance members of the object, which means that the object can maintain some state, And take advantage of these state confidence during callback method execution).
Covariance and contravariance of delegates
When binding a method to a delegate, both C # and the CLR allow reference types to be covariant and contravariant
Covariant: The return type of a method is a type derived from the return type of the delegate
contravariant: The parameter type obtained by the method is the base class of the delegate parameter type.
For example:
1 delegate Object CallBack (FileStream file); 2 3 string SomeMethod (Stream stream);
In the preceding code, the return type (string) of SomeMethod is derived from the return type (object) of the delegate, so that covariance is possible.
The SomeMethod parameter type (Stream) is the base class of the delegate's parameter type (FileStream), so the contravariance is possible.
So if you change the string SomeMethod (Stream stream) to Int SomeMethod (Stream stream);
Then the C # Editor will make an error.
Description: Covariance and contravariance can only be used for reference types, not for value types and void, because the storage structure of a value type is variable, and the storage structure of a reference type is always a pointer.
the inverse and covariance of delegates and interfaces--generic type parameters
each generic type parameter of a delegate can be marked as a covariant or inverse variable, so that we can transform one variable of a generic delegate type into another variable of the same delegate type, or a different type of generic parameter .
invariants: Indicates that the generic type parameter cannot be changed.
Inverse variable: Indicates that a generic type parameter can be changed from a base class to a derived class of that class . In C #, you use the in keyword to mark generic type parameters in the form of an inverse variable, and the inverse variable generic parameter can only appear in the input position.
Covariance: Represents a generic type parameter that can be changed from a derived class to its base class , in C #, with an out-tagged generic type parameter as a covariant. The covariance can only appear in the output location. For example, the method returns a value type.
Public Delegate TResult func<in t,out tresult> (T Arg);
In this line of code, the generic type parameter T is marked with the IN keyword so that it becomes an inverse variable, and TResult is marked with the Out keyword, which makes him a co-variable.
When using delegates to get generic parameters and return values, use contravariance and covariance to specify the in and out keywords as much as possible. When using an interface with a generic type parameter, you can also mark its type parameter as an inverse variable and a covariant, as in the following code:
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
1 public interface Ienumerator<out t>: IEnumerator 2 {3 Boolean MoveNext (); 4 T Current{get;} 5} 6//CO The Unt method accepts arguments of any type 7 public int count (ienumerable<object> coll) {} 8 9//Call count to pass a ienumerable<string>10 int i = Count (new[]{"Albin"});
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
In- depth entrusted disclosure
First, declare a delegate:
1 internal delegate void Delegatebackcall (int val);
To reverse-compile by viewing a delegate:
650) this.width=650; "style=" WIDTH:1096PX; src= "Http://images.cnitblog.com/i/309758/201407/061335189349181.jpg"/ >
There are four ways to see this in Delegatebackcall by deserializing: constructors, BeginInvoke, EndInvoke, Invoke, and you can see that the Delegatebackcall class is inheriting the system. Multicasedelegate (in fact all delegates are derived from it. Essentially: System.multicasedelegate is derived from System.Delegate. And the latter derives from System.Object),
Here we also see in the first constructor, there are two parameters, one is an object reference, one is a reference to the callback method of an integer, in fact, all delegates have a constructor, and the constructor parameters as just said (an object reference, an integer referencing the callback method) inside the constructor, These two parameters are saved in _target (when the delegate object wraps a static method, this field is null when the delegate object wraps an instance method that refers to the object that the callback method is manipulating.) and _method (an internal integer value, which the CLR uses to identify the method to be called back), the two private fields are given, and the constructor will also _invocationlist (when constructing a delegate chain, it can reference a delegate array, which is usually null) field is set to null
Each delegate object is actually a wrapper that wraps a method and an object to manipulate when the method is called
The following code:
1 Delegatebackcall delegateinstance = new Delegatebackcall (program.instancetoconsole); 2 3 Delegatebackcall DelegateSta tic = new Delegatebackcall (statictomessage);
In this delegateinstance and delegatestatic variables reference two independent, initialized good Delegatebackcall delegate objects. In the delegate class (Delegate), two read-only public instance properties are defined, target and method, which we can query when given a delegate object reference. Target returns the value in the _target field we said earlier, pointing to the object that the callback method is manipulating. That is, if it is a static method then the target has an internal conversion mechanism for the Null,method property, which converts the value in the private field _methodptr to a MethodInfo object and returns it. The method name that we passed.
When we invoke a variable of a delegate object, the Invoke method of the delegate object is invoked when the code generated by the compiler is actually called, for example, in the Counter function, Foo (val) actually resolves to us as-Foo.invoke (Val); Invoke is to invoke the delegate object in a synchronous manner to maintain each method. This means that the caller must wait for the call to finish before continuing. Invoke invokes the wrapped callback method on the specified object via _target and _methodptr, and the signature of the Invoke method is consistent with the signature of the delegate.
Delegate-Chaining (multicast delegation) with delegate callback for many methods
A delegate chain is a collection of delegate objects. By using a delegate chain, you can invoke any method represented by a delegate in the collection. In other words, a delegate object can maintain a list of callable methods instead of a single method, adding multiple methods to a delegate object without direct allocation, in this C # The compiler gives us the overloaded +=,-= operator,
Let's take a generation of code for example, the code is as follows:
1 Delegatebackcall delegateinstance = new Delegatebackcall (program.instancetoconsole); 2 3 Delegatebackcall DelegateSt atic = new Delegatebackcall (statictomessage);
This code can be modified like this:
1 Delegatebackcall delegatefb = null;2 3 Delegatefb + = new Delegatebackcall (program.instancetoconsole); 4 5 DelegateFb + = New Delegatebackcall (Statictomessage);
In fact, this is the trust chain (also called multicast delegation),
So let's reverse-compile:
650) this.width=650; "src=" http://images.cnitblog.com/i/309758/201407/062354435591151.jpg "/>
We found that the inside of the + = operation was added to the chain by the static method of the delegate class, combine, after the anti-compilation.
In this combine a new delegate object is constructed, the new delegate object initializes its private fields _target and _methodptr, and the _invocationlist field is initialized to refer to an array of delegate objects. The first element of the array is initialized to a delegate that wraps the Program.instancetoconsole method, and the second element of the array is initialized to refer to the delegate that wraps the Statictomessage method, and then internally iterates through each delegate for output.
Similarly, when we want to remove a delegate from a delegate object collection, we can pass the-= operator.
Delegatebackcall DELEGATEFB = null; DELEGATEFB-= new Delegatebackcall (new program (). Instancetoconsole); DELEGATEFB-= new Delegatebackcall (statictomessage);
So the same goes for anti-compilation:
650) this.width=650; "src=" http://images.cnitblog.com/i/309758/201407/070009321995167.jpg "/>
The inside of it is removed by the remove function. When the Remove method is called, it iterates through the delegate array that is maintained within the referenced delegate object, remove by looking for a delegate whose _target and Methodptr fields match the field in the second argument. If a matching delegate is found and only one data item is left in the array after the deletion, the data item is returned, and if found, and more than one data item is left in the array, the _invocationlist array created and initialized in the new delegate object will reference all the data items in the original array ( Removed exception), remove returns null if only one element is removed. Remove only one delegate at a time. does not delete all.
Here is a method: Getinvocationlist, which operates an object derived from MulticastDelegate, returns an array of delegate references, each of which points to a delegate in the delegate chain. Inside, Getinvocationlist constructs and initializes an array so that each of its elements refers to a delegate in the chain, and then returns a reference to the array, and if the _invocationlist field is null and returns only one element, then it is the delegate instance itself.
The following code:
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
Delegatebackcall DELEGATEFB = null; DELEGATEFB + = new Delegatebackcall (new program (). Instancetoconsole); DELEGATEFB + = new Delegatebackcall (statictomessage);p rivate static void Getcomponentreport (Delegatebackcall DELEGATEFO) {if (Delegatefo! = null) {delegate[] arraydelegates = Delegatefo. Getinvocationlist (); foreach (Delegatebackcall delegateback in arraydelegates) {//.... Omitted}}}
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
Too many delegate definitions? -A generic delegate
The. NET Freamework supports generics, so we can define generic delegates to reduce the number of delegate declarations, which can reduce the type count in the system and simplify coding.
650) this.width=650; "src=" http://images.cnitblog.com/i/309758/201407/070031076995217.jpg "/>
There are 17 action delegates available in. NET freamework, from no parameters up to a maximum of 16 parameters, which should be sufficient for development.
In addition, the. NET Freamework provides 17 function functions that allow the callback method to return a value.
650) this.width=650; "src=" http://images.cnitblog.com/i/309758/201407/070031346525851.jpg "/>
When you use a delegate that gets a generic argument and return value, you can take advantage of contravariance and covariance,
The simple notation of delegates--1:LAMBDA expressions, anonymous functions--instead of defining callback functions.
In fact, these can be summed up in C # syntax sugar, which provides us programmers with a simpler and more respectable way.
For example:
You do not need to define a callback function, directly using the form of a lambda expression, to create an anonymous function to execute the method body.
Private Static Void callbacknewdelegateobject () {ThreadPool.QueueUserWorkItem (o = Console.WriteLine (o), 5); }
The first argument passed to the QueueUserWorkItem method is a lambda expression that can be used where the compiler expects to see a delegate, and a new private method is automatically defined in the class after the compiler sees the lambda expression. This method is called anonymous method, the so-called anonymous method, not without a name, its name is automatically created by the compiler. In this note, the anonymous function is marked as static and is private because the code does not have access to any instance members. However, you can refer to any static field or static method in a class. Thus the performance of the courseware anonymous function is more efficient than the instance method because it does not require an additional this parameter.
2: Simplified syntax--local variables do not need to be wrapped manually into the class to be passed to the callback method
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
public static void usinglocalvariablesinthecallback (Int num) { int[] i = new int[num]; 4 Autoresetevent done = new autoresetevent (false); for (int n = 0; n < i.length; n++) { threadpool.queueuserworkitem (obj => { int nums = (Int32) obj; i[nums] = nums * nums; if (Interlocked.decrement (ref num) == 0) { done. Set (); } }, n); } done. WaitOne (); for (int n = 0; n < i.length; n++) { console.writeline ("Index {0},i {1} ", n, i[n]); }}
650) this.width=650; "src=" Http://common.cnblogs.com/images/copycode.gif "alt=" Copy Code "/>
In the method body of a lambda expression, if the method body is a separate function, how do we pass the value of the variable to the method? So now the code in our anonymous function method body needs to be extracted into a separate class, and then the class assigns each value by the field, and then the Usinglocalvariablesinthecallback method must construct an instance of the class, Initializes the field in this instance with the value of the local variable defined by the method, and then constructs a delegate object that is bound to the instance method.
This article is from the "Albin" blog, make sure to keep this source http://albin.blog.51cto.com/9047703/1439012