Introduced. NET for delegation (i)
----Microsoft. NET Platform series of article four
callback function
Callback functions are indeed one of the most useful programming mechanisms so far. The C run-time qsort function uses the callback function to sort the array elements. In Windows, the callback function is the window procedure, the hook process, the asynchronous procedure call, and the current Microsoft. NET Framework, the callback method is used throughout the callback process. People can register callback methods to get load/unload notifications, unhandled exception notifications, database/window state modification notifications, file system modification notifications, menu item selections, completed asynchronous operation notifications, filter a set of entries, and so on.
In C + +, the address of a function is the memory address. This address will not be accompanied by any additional information, such as the number of parameters of the function, the type of the parameter, the type of return value of the function, and the invocation specification of the function. In short, C + + callback functions are not type-safe.
In the. NET Framework, the callback function is reused as it does in Windows unmanaged programming. The difference is in. NET Framework provides a type-safe mechanism called delegation (delegates). Let's take a look at the delegation's statement first. The following code shows how to declare, create, and use a delegate:
//
Using System;
The using system.winforms;//is in the Beta2 version: System.Windows.Forms
Using System.IO;
Class Set {
Private object[] items;
Public Set (Int32 NumItems) {
Items = new Object[numitems];
for (Int32 i = 0; i < NumItems; i++)
Items[i] = i;
}
Define Feedback, type delegate
(Note: This type is nested within the Set class)
public delegate void Feedback (
Object value, Int32 item, Int32 NumItems);
public void ProcessItems (Feedback Feedback) {
for (Int32 item = 0; Item < items. Length; item++) {
if (feedback!= null) {
Once the callback is specified, they are called
Feedback (Items[item], item + 1, items. Length);
}
}
}
}
Class App {
[STAThreadAttribute]
static void Main () {
Staticcallbacks ();
Instancecallbacks ();
}
static void Staticcallbacks () {
Create a set object with five items
Set setofitems = new set (5);
Process items, Feedback=null
Setofitems.processitems (NULL);
Console.WriteLine ();
Process items, Feedback=console
Setofitems.processitems (New Set.feedback (App.feedbacktoconsole));
Console.WriteLine ();
Processing projects, Feedback =msgbox
Setofitems.processitems (New Set.feedback (App.feedbacktomsgbox));
Console.WriteLine ();
Process items, feedback = Console and MsgBox
Set.feedback fb = null;
FB + + new Set.feedback (app.feedbacktoconsole);
FB + + new Set.feedback (App.feedbacktomsgbox);
Setofitems.processitems (FB);
Console.WriteLine ();
}
StreamWriter sw = new StreamWriter ("Status", true);
Sw. WriteLine ("Processing item {0} of {1}: {2}.")
Item, NumItems, value);
Sw. Close ();
}
}
//
Note the set class at the top of the code. Suppose this class contains a set of items that will be handled separately. When you create a set object, pass the number of items it is manipulating to its constructor. The constructor then creates an array of objects (Objects) and initializes each integer value.
In addition, the set class defines a public delegate that indicates the signature of a callback function. In this example, the delegate feedback determines a method with three arguments (the first argument is object, the second and third arguments are INT32 types) and returns void. In a sense, delegation is much like a type definition (typedef) that represents a function address in C + +.
In addition, the set class defines a public method: ProcessItems. This method has a parameter feedback--a reference to the delegate feedback object. ProcessItems iterates through all the array elements and invokes the callback method (which is specified by the feedback variable) for each element, which is passed to handle the item values, number of items, and the number of elements in the array that the callback method passes in a different way. You can see that the callback method can handle each item in any way it chooses.
To invoke a static method using delegation
The Staticcallbacks method demonstrates a variety of different ways of callback delegation. This method first constructs a set object, telling it that the object creates an array of five object elements. Then call ProcessItems, whose feedback argument is null in the first call. ProcessItems renders a method that implements some action for each set-manipulated project. In the first example, because the feedback parameter is NULL, no callback method is invoked when each item is processed.
The second example creates a new Set.feedback delegate object, which is a method wrapper that allows the invocation of a method to be invoked indirectly through this wrapper. For a constructor of type feedback, the name of the method (App.feedbackconsole) is passed as a parameter of the constructor, which means that the method is wrapped. The reference returned from the new operator is then passed to ProcessItems. Now, when ProcessItems is executed, it calls the app-type Feedbacktoconsole method to process each item in the collection. Feedbacktoconsole simply outputs a string to the console, indicating which item was processed and what the value of the project was.
The third example is essentially the same as the second example. The only difference is that the feedback delegate object wraps another method: App.feedbacktomsgbox. This method creates a string that indicates which item is processed and what the value of the item is. The string is then displayed in an information box.
The fourth example is also the last example of a static call demonstrating how to link delegates together to form a chain. In this example, first create a key to the feedback delegate object's reference variable fb and initialize it to null. This variable points to the header of the delegated list. A null value indicates that there are no nodes in the linked list. Then, the feedback delegate object is constructed, and the object wraps the call to the app Feedbacktoconsole method. In C #, the + + operator is used to add an object to a linked list in the FB reference. FB points to the header of the linked list at this point.
Finally, you construct another feedback delegate object that wraps the invocation of the app Feedbacktomsgbox method with this object. The + = operator in C # is once again used to add objects to the list of FB references, and FB is updated by the header of the new list. Now, when the ProcessItems is executed, the header pointer to the feedback delegation list is passed to it. Within ProcessItems, the line of code that invokes the callback method actually terminates the invocation of the callback method that was wrapped by the delegate object in the list. That is, for each project that is iterated, the feedbacktoconsole is invoked, and then the Feedbacktomsgbox is called immediately. In subsequent articles I will discuss in detail the processing mechanism for the delegation chain.
It is important to note that everything is type safe in this example, for example, when constructing a feedback delegate object, the compiler guarantees that the Feedbacktoconsole and Feedbacktomsgbox methods of the app have the exact prototype, As defined by the feedback delegate. Both two methods must have three parameters (Object,int32 and Int32), and two methods must have the same return type (void). If the method prototype does not match, the compiler issues the following error message: "Error cs0123:the signature of" App.feedbacktomsgbox () ' does not match this delegate
Type "--meaning that the signature of the App.feedbacktomsgbox () method does not match the type of the delegate.
Invoke Instance method
We discussed earlier how to invoke a static method using delegation. However, delegation can also be used to invoke instance methods for specific objects. When invoking an instance method, the delegate needs to know the instance of the object it is going to manipulate with the method.
To understand the callback mechanism of the instance method, let's look back at the Instancecallbacks method in the previous code. This code is very similar to the case of a static method. Note that the App object is created after the set object is created. This App object is only created, and there is no other content in the example. When a new feedback delegate object is created, its construction is uploaded to the appobj. Feedbacktofile. This will cause the delegate to wrap a reference to the Feedbacktofile method, Feedbacktofile is an instance method (Non-static). When this instance method is invoked, the object referenced by Appobj is manipulated (as a hidden pass parameter). The Feedbacktofile method works a bit like Feedbacktoconsole and Feedbacktomsgbox, but it opens a file and adds the processed item string to the end of the file.
Uncover the mystery of delegation
On the surface, delegation seems to be easy to use: Delegate keyword definitions in C #, construct their instances in the same way as the new operator, invoke the callback method with syntax similar to the method invocation (instead of using the method name, but using the variable that refers to the delegated object).
However, the actual operating mechanism of a delegate is much more complex than the process described in the preceding example. Many of the processes that the compiler and the common language runtime (CLR) have done behind the scenes hide these complexities, and in this section we will focus on how compilers and the CLR work together to implement delegated mechanisms. This knowledge will greatly enrich your understanding of delegation and will tell you how to use them effectively. We will also involve some additional delegated features that can be used in programming.
Let's start with the following line of code:
public delegate void Feedback (
Object value, Int32 item, Int32 NumItems);
When the compiler sees a line of code, it produces a complete class definition, and the code looks like this:
//
public class Feedback:System.MulticastDelegate {
Construction device
Public Feedback (Object target, Int32 methodptr);
Method is the same as the prototype of the source code description
public void Virtual Invoke (
Object value, Int32 item, Int32 NumItems);
Method allows asynchronous callbacks, and subsequent articles will discuss these methods
Public virtual IAsyncResult BeginInvoke (
Object value, Int32 item, Int32 NumItems,
AsyncCallback callback, Object object);
public virtual void EndInvoke (IAsyncResult result);
}
//
In fact, by using the ILDasm.exe program to check the result module (figure III), you can see that the compiler does automatically generate this class.
Figure three check the compiler-generated class
In this example, the compiler has defined a class that derives from the System.MulticastDelegate type called feedback, which is defined in the Framework class library (frame class libraries). You know, all delegate types are derived from MulticastDelegate. In this example, the feedback class is public, because its type in the source code is defined as publicly. If a private (private) or a protected (protected) type is defined, the feedback class generated by the compiler will also be a private or protected type. You should note that the delegate class may be defined in a class (as in the example feedback is defined in the Set Class), or the delegate may be defined as a global type. In essence, delegation can be thought of as a class, where delegates can be defined anywhere in the definition class.
Because all delegates are derived from MulticastDelegate, they inherit multicastdelegate domains, properties, and methods. Of all these members, you should pay special attention to three private fields:
Private domain for delegate type:
Domain type description
_target System.Object refers to an object that should be manipulated when a callback function is invoked. Used for instance method callbacks
_methodptr System.Int32 Internal integral type, which the CLR uses to indicate the method that is being invoked
_prev System.MulticastDelegate refers to another delegated object, usually null
All delegates have constructors for two parameters: one parameter is an object reference, and one is an integer that refers to the callback method. However, if you examine the source code, you will find that you understand such things as app.feedbacktoconsole or appobj. The feedbacktofile is passed using a value. Your sensitivity will tell you that the code cannot be compiled!
However, the compiler knows that a delegate is created, and the compiler resolves the source code to determine which object and method to reference. An object reference is passed as a target parameter and a method marked with a particular Int32 value (obtained from a methoddef or methodref metadata symbol) is passed as a methodptr parameter. For static methods, NULL is passed as the target parameter. Inside the constructor, the two parameters are stored in their corresponding private (privacy) fields.
In addition, the constructor resets this field to null. This field is used to create a list of MulticastDelegate objects. Now we're ignoring the _prev domain for a while and we'll discuss it in more detail in later articles.
Each delegated object is actually a method wrapper, and when the method is invoked, the affected object is manipulated. The MulticastDelegate class defines two read-only public instance properties: Target and method. Given a delegate object reference, you can query the properties of it. If the method is called back, the target property returns a reference to the object that will be manipulated. If the method is static, Target returns NULL. The method property returns the System.Reflection.MethodInfo object that marks the callback methods.
You can use this information in several ways. One way is to check whether a delegated object refers to an instance method of a particular type:
//
Boolean Delegatereferstoinstancemethodoftype (
MulticastDelegate d, type type) {
You should also write code to check whether the callback method is by a special name (such as Feedbacktomsgbox):
//
Boolean Delegatereferstomethodofname (
MulticastDelegate D, String methodname) {
return (D.method.name = = methodname);
}
//
Now that you know how to construct a delegate object, let's talk about how the callback method is invoked. For the sake of convenience, we still use
ProcessItems in the Set class:
//
public void ProcessItems (Feedback Feedback) {
for (Int32 item = 1; Item <= items. Length; item++) {
if (feedback!= null) {
If any callbacks are specified, they are called
Feedback (Items[item], item, items. Length);
}
}
}
//
The line of code below the comment line is the invocation callback method. Take a closer look at the code, which calls the feedback function and passes three arguments. But feedback does not exist. Again, the compiler knows that feedback is a variable that references a delegated object, and that the compiler produces actual code to invoke the Invoke method of the delegated object. In other words, the compiler sees the following line of code:
Feedback (Items[item], item, items. Length);
The compiler produces the same results as the following line of source code:
Feedback. Invoke (Items[item], item, items. Length);
In fact, you can see that by using the ILDasm.exe program to check the ProcessItems code results (as in Figure V).
ProcessItems of Set class after decomposition of Figure five
Figure five shows the Microsoft mediation language for the ProcessItems method in the set type. Where the red arrow points to the instruction calls the Set.feedback invoke method. If you modify the source code to explicitly invoke the Invoke method, the C # compiler complains that the error message is: "Error cs1533:invoke cannot be called directly on a delegate"-- This means that invoke cannot be invoked directly against a delegate. C # does not allow you to explicitly invoke invoke (however, but other compilers can).
You will remember that when the compiler defines the feedback class, it also defines the Invoke method. When Invoke is invoked, it uses the private _target and _methodptr fields to invoke the desired method for a particular object. Note that the signature of the Invoke method exactly matches the signature of the delegate. That is, the feedback delegate takes three parameters and returns void, so the Invoke method must also take three identical parameters and return void.
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.