C # Delegate and event nature

Source: Internet
Author: User

C # Delegate and event nature
In C #, delegation and events are very important components, and it is essential to master the nature of delegation and events. To explore the essence, write the following code to copy the code using System; using System. collections. generic; using System. linq; using System. text; using System. threading; using System. threading. tasks; namespace ConsoleApplication1 {class Program {static void Main (string [] args) {Water water = new Water (); water. waterBoils + = water_WaterBoils; water. waterBoils + = water_WaterBoils2; water. degreeRise (); Console. readLine ();} static void water_Wa TerBoils (object sender, WaterBoilsEventArgs args) {Console. writeLine (string. format ("sender: {0}", sender. toString (); Console. writeLine (string. format ("args: {0}", args. curentDegree. toString ();} public static void water_WaterBoils2 (object sender, WaterBoilsEventArgs args) {Console. writeLine (string. format ("sender_2: {0}", sender. toString (); Console. writeLine (string. format ("args_2: {0}", args. cur EntDegree. toString ();} public delegate void WaterBoilsEventHandler (object sender, WaterBoilsEventArgs args); public class WaterBoilsEventArgs: EventArgs {public int CurentDegree {get; set ;}} public class Water {public event WaterBoilsEventHandler WaterBoils; public int curentDegree = 0; public void DegreeRise () {for (var n = 99; n <200; n ++) {Thread. sleep (1000); if (n> = 100) {if (WaterBoils! = Null) {WaterBoils (this, new WaterBoilsEventArgs () {CurentDegree = n}); // WaterBoils. invoke (this, new WaterBoilsEventArgs () {CurentDegree = n}) ;}}}}copy the Code to introduce this section: defines a delegate WaterBoilsEventHandler, a class Water, the DegreeRise Method of Water triggers the WaterBoils event, one event parameter WaterBoilsEventArgs, and one Main method. since it depends on the nature of delegated events, you can use the decompilation tool (Reflector) to view the compiled code snippets. First, let's take a look at the code after delegated Compilation: copy the code. class public auto ansi sealed WaterBoilsEventHandler e Xtends [mscorlib] System. multicastDelegate {. method public hidebysig specialname rtspecialname instance void. ctor (object 'object', native int 'method') runtime managed {}. method public hidebysig newslot virtual instance class [mscorlib] System. IAsyncResult BeginInvoke (object sender, class ConsoleApplication1.WaterBoilsEventArgs args, class [mscorlib] System. asyncCallback callback, object 'object ') Runtime managed {}. method public hidebysig newslot virtual instance void EndInvoke (class [mscorlib] System. IAsyncResult result) runtime managed {}. method public hidebysig newslot virtual instance void Invoke (object sender, class ConsoleApplication1.WaterBoilsEventArgs args) runtime managed {}} copy the code from the decompilation IL code: 1. A custom delegate is essentially a class with the Invoke, BeginInvoke, and Endinvoke methods to support synchronous and asynchronous execution, with no return value for Invoke; BeginInvo Ke returns IAsyncResult. IAsyncResult can be used as an EndInvoke parameter to end execution. 2. custom delegation inherits from MulticastDelegate, so that the custom Delegate can be "multicast", that is, multiple delegates can be bound; (the MulticastDelegate class inherits from Delegate again) next let's take a look at how "Multicast" is implemented: There are two methods in MulticastDelegate: CombineImpl and RemoveImpl, respectively, to bind and unbind the delegate; there is an internal object (will be converted to object [] in use) _ invocationList to store the MulticastDelegate object. There are other methods to accomplish this together. From the above, we can see that the delegate can be bound to execute multiple methods. Why is there an event? I think this problem may be from the perspective of language design, the design starting point of delegation is to avoid pointer variables in C, C ++, etc. The Delegate wraps the address and decompile the Delegate class. The following member QQ20140712133307 _ methodPtr is found: method pointer. A Delegate object maintains the reference address of a method. Is there any discrepancy when using the Delegate? C # And. net 3.5 advanced programming version 4 has the following explanation: "If we do not define the delegate member variable as private, the caller can directly access the delegate object, in this way, the caller can assign a variable to a new delegate object (in fact, the list of methods to be called is deleted). Worse, the caller can directly call the delegate call list." Here is a serious problem: 1. for example, if two objects are registered, A has already registered A method. When B registers, it deletes the method registered by A, and B can also operate on the method registered by. This kind of unfriendly is intolerable. C # provides the event keyword to solve the problem for us. Kids shoes who have used the event may be impressed. In other classes other than declaring the event, if you call the event, you can only do two things: 1. bind method reference, 2. unbind method reference. This is an event restriction. Follow this line of thought to see how the events in C # are completed. First, let's take a look at the decompilation result of the Water class and copy the code. class public auto ansi beforefieldinit Water extends [mscorlib] System. object {. event ConsoleApplication1.WaterBoilsEventHandler WaterBoils {. addon instance void ConsoleApplication1.Water: add_WaterBoils (class ConsoleApplication1.WaterBoilsEventHandler ). removeon instance void ConsoleApplication1.Water: remove_WaterBoils (class ConsoleApplication1.WaterBoilsEventHandler )}. Method public hidebysig specialname rtspecialname instance void. ctor () cel managed {}. method public hidebysig instance void DegreeRise () cel managed {}. field public int32 curentDegree. field private class extends WaterBoils} the method used to copy the code add_WaterBoils is defined as follows: copy the code public void add_WaterBoils (WaterBoilsEventHandler value) {WaterBoilsEventHandler handler2; WaterBoilsE VentHandler waterBoils = this. waterBoils; do {handler2 = waterBoils; WaterBoilsEventHandler handler3 = (WaterBoilsEventHandler) Delegate. combine (handler2, value); waterBoils = Interlocked. compareExchange <WaterBoilsEventHandler> (ref this. waterBoils, handler3, handler2);} while (waterBoils! = Handler2);} the method used to copy the code remove_WaterBoils is defined as follows: copy the code public void remove_WaterBoils (WaterBoilsEventHandler value) {WaterBoilsEventHandler handler2; WaterBoilsEventHandler water. waterBoils; do {handler2 = waterBoils; WaterBoilsEventHandler handler3 = (WaterBoilsEventHandler) Delegate. remove (handler2, value); waterBoils = Interlocked. compareExchange <WaterBoilsEventHandler> (ref this. waterBoils, Handler3, handler2);} while (waterBoils! = Handler2);} copy the code and you can see: 1. two methods are added: add_WaterBoils and remove_WaterBoils; 2. A private WaterBoils variable of the WaterBoilsEventHandler type is added, which is the same as the declared event object name, which may lead to a bit of confusion :. event ConsoleApplication1.WaterBoilsEventHandler WaterBoils is a bit like an internal class structure, and this "class" has two methods. Temporarily put this confusion down. 3. The add_WaterBoils and remove_WaterBoils methods both maintain the private field WaterBoils. After knowing this, let's see how it was called during registration: copy the code private static void Main (string [] args) {Water water = new Water (); water. waterBoils + = new WaterBoilsEventHandler (Program. water_WaterBoils); water. waterBoils + = new WaterBoilsEventHandler (Program. water_WaterBoils2); water. degreeRise (); Console. readLine () ;}copy the Code. This is the C # code method. You cannot see any results. Check the IL Code as follows: copy the code. method private hidebysig static void Main (string [] args) cel managed {. entry Point. maxstack 3. locals init ([0] class ConsoleApplication1.Water water) L_0000: nop L_0001: newobj instance void ConsoleApplication1.Water ::. ctor () L_0006: stloc.0 L_0007: ldloc.0 L_0008: ldnull L_0009: ldftn void ConsoleApplication1.Program: water_WaterBoils (object, class Identifier) L_000f: newobj instance void identifier ::. ctor (ob Ject, native int) L_0014: callvirt instance void ConsoleApplication1.Water: add_WaterBoils (class verification) L_0019: nop L_001a: ldloc.0 L_001b: ldnull L_001c: ldftn void metadata: Upload (object, class ConsoleApplication1.WaterBoilsEventArgs) L_0022: newobj instance void ConsoleApplication1.WaterBoilsEventHandler ::. ctor (object, native I Nt) L_0027: callvirt instance void response: add_WaterBoils (class response) L_002c: nop L_002d: ldloc.0 L_002e: callvirt instance void response: DegreeRise () L_0033: nop L_0034: call string [mscorlib] System. console: ReadLine () L_0039: pop L_003a: ret} copy the code to analyze the three lines from L_0009 to L_0014: L_0009: Push the pointer of the water_WaterBoils Method to the computing stack L_000f: Create a WaterBoilsEventHandler delegate object L_0014: Call add_WaterBoils and push the result to the computing stack. Note the following code: "leleapplication1.water: add_WaterBoils, add_WaterBoils is the method of leleapplication1.water class object. The confusion above looks like an "internal class", but it doesn't matter. This Code shows that the event registration is to call the compilation method add_WaterBoils to maintain the method reference address contained in the delegate to the compilation private attribute WaterBoils. Therefore, the event is the syntactic sugar, which saves the time for coding, and the event is triggered using a special event to handle it, showing the completeness of the language, the real implementation is implemented by the compiler to generate the delegate object and other processing code.

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.