[C # Basic Knowledge series] topic: anonymous method analysis

Source: Internet
Author: User

introduction:

I feel that I haven't updated the blog in a long time, I'm really sorry for everyone. In this topic, anonymous methods will be introduced. Anonymous methods can be understood by looking at the name. Of course, there is no name method (in real life, there are many such anonymous processes, such as anonymous voting, anonymous reporting, etc., I believe Microsoft is sure in naming It is based on the examples in life), but the understanding of anonymous methods is not just this sentence (this sentence refers to a method without a name), it still has a lot of content, the following specifically introduces what the anonymous method has

 

1. Anonymous method

 I used to think that the anonymous method was proposed in C # 3.0. The reason why I thought so was mainly because I knew that the anonymous type was proposed in C # 3.0. After learning the C # features of the system, I discovered that the anonymous method was already proposed in C # 2.0. As can be seen from the development of the features, the Microsoft team is very planned. It has been planned, and the following features have evolved from the previous features. The reason why there are new features is mainly to facilitate everyone to write programs, reduce the work of programmers, and let the compiler perform more complex operations to make the program You can focus on implementing your system ’s business logic method (this is also Microsoft ’s main idea and the good user experience emphasized by most software), but the anonymous method is also built on the basis of delegation in C # 1.0 (At the same time, C # 2.0 has enhanced delegation, and proposed a generic delegation, as well as a delegation parameter And inverter, you can refer to the previous topic in this series for details. Here is a detailed introduction to why the anonymous method is based on the delegation (the delegation is the method packaging, the anonymous method is also the method, but the anonymous method is not The name method only, so the delegate can also wrap anonymous methods).

First of all, let ’s first introduce the concept of anonymous methods. Anonymous methods-methods without names (methods are the concept of functions in mathematics). Anonymous methods just do n’t specify a name in the source code we write. In fact, the compiler will help An anonymous method generates a name, but because there is no name in the source code, the anonymous method can only be called when it is defined, and cannot be called elsewhere (anonymous methods embed the method definition and method implementation together) , Let's take an example to see the use of anonymous methods and how they are related to delegation:

Copy code
Copy code
namespace anonymous method Demo
{
    class Program
    {
        // Define voting delegate
        delegate void VoteDelegate (string name);

        static void Main (string [] args)
        {
            // Instantiate the delegate object
            VoteDelegate votedelegate = new VoteDelegate (new Friend (). Vote);

            // Code using anonymous methods
            // An anonymous method inlined a delegate instance (can be compared with the code of the delegate instantiation above)
            // After using the anonymous method, we do not need to define a Friend class and a separate voting method
            // This can reduce the amount of code, the code is less, it is much easier to read, so that it will not be confused by the definition of too many callback methods
            // VoteDelegate votedelegate = delegate (string nickname)
            // {
            // Console.WriteLine ("nickname: {0} came to vote for Learning Hard", nickname);
            //};

            // Call the Vote () method by calling the bracket
            votedelegate ("SomeBody");
            Console.Read ();
        }
    }

    public class Friend
    {
        // friend's voting method
        public void Vote (string nickname)
        {
            Console.WriteLine ("Nickname: {0} to vote for Learning Hard", nickname);
        }
    }
}
Copy code
Copy code
Because I participated in the 51 Blog Contest some time ago, I also pulled a lot of friends to help vote in the voting stage, so in order to thank them, so the above uses the voting as an example to introduce the anonymous method. The benefits of the anonymous method have been explained in the comment section , Can help us reduce the amount of written code, easy to read, but the above places can use anonymous methods instead of delegation? Do we need to use anonymous methods to replace all places where delegation is used? This is not the case, because anonymous methods are methods without names, so they cannot be called elsewhere, so they do not have multiplexing effects, and anonymous methods automatically form "closures" (if friends who do not understand closures can refer to These two links: http://baike.baidu.com/view/648413.htm and http://zh.wikipedia.org/wiki/closure_(computer science), I understand that the closure is probably one When another function (called internal function) is called in the function (external function), when the internal function uses the variable in the external function, this may form a closure. For specific concepts, please refer to the two links above, Relevant examples will be given in the later part to help you understand, because anonymous functions will form closures, which will extend the life cycle of variables). So if the method of delegation packaging is relatively simple (just like the output line of the above code is only a single line), and the frequency of this method used in other places is very low, then you can consider using anonymous methods instead of delegation.

Second, use anonymous methods to ignore the commission parameters

The first part mainly introduces the concept of anonymous methods, uses and introduces why I understand why anonymous methods are proposed (in order to facilitate us to instantiate the delegate instance, the delegate method can be inlined through the anonymous method, so as to avoid defining an additional instance Method, reduce the amount of code, which is conducive to reading), in this section will introduce another benefit of anonymous methods-ignore the delegate parameters. The following is a sample code to help you understand, there will be detailed comments in the code, so I wo n’t say much here, just look at the code:

Copy code
Copy code
namespace ignores the delegate parameter Demo
{
    class Program
    {
        static void Main (string [] args)
        {
            // Timer class generates periodic events in the application
            System.Timers.Timer timer = new System.Timers.Timer ();

            // This value indicates whether Elapsed event is raised
            timer.Enabled = true;

            // Set the interval of Elapsed event
            timer.Interval = 1000;

            // Elapsed event occurs when the interval is reached, the time interval is set to 1 second in the front,
            // So the Elapsed event will be triggered every second, so the timer_Elapsed method will be called back to output the current time
            // timer.Elapsed + = new System.Timers.ElapsedEventHandler (timer_Elapsed);

            // At this time, the parameters in the timer_Elapsed method are not needed at all, so we can use anonymous methods to omit the delegation parameters
            // Our code is more concise after omitting the parameters, how comfortable it is to see
            // We often don't use the delegated parameters in the development of WinForm programs, at this time we can use anonymous methods to omit the parameters
            timer.Elapsed + = delegate
            {
                Console.WriteLine (DateTime.Now);
            };

            Console.Read ();
        }

        public static void timer_Elapsed (object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine (DateTime.Now);
        }
    }
}
Copy code
Copy code
The running result is:



The above code uses an anonymous method to omit the delegate parameter, but for the compiler, it will still call the delegate constructor to instantiate the delegate, so if the anonymous method can be converted to multiple delegate types, if the delegate is omitted at this time Parameters, the compiler does not know which specific delegate type to convert the anonymous method to, so a compile-time error will occur at this time, you must manually specify the parameters to tell the compiler how to instantiate the delegate, the following to create a thread As an example to help you understand the problems caused by anonymous methods omitting delegate parameters (because the creation of threads involves two delegate types: public delegate void ThreadStart () and public delegaye void ParameterizedThreadStart (objec obj)):

Copy code
Copy code
class Program
    {
        static void Main (string [] args)
        {
            new Thread (delegate ()
                {
                    Console.WriteLine ("Thread One");
                });

            new Thread (delegate (object o)
            {
                Console.WriteLine ("Thread Two");
            });

            new Thread (delegate
            {
                Console.WriteLine ("Thread Three");
            });
            Console.Read ();
        }
    }
Copy code
Copy code
At this time, the third thread creation code will have the following compilation error:



Three, capture variables in anonymous methods

 As mentioned in the previous introduction, when an anonymous method is used, a closure is formed. Closure refers to capturing variables in the anonymous method. In order to better understand the concept of closure, you first need to understand two concepts-external variables and captured External variables, the following two examples to explain these two concepts:

Copy code
Copy code
class Program
    {
        // Define closure delegate
        delegate void ClosureDelegate ();

        static void Main (string [] args)
        {
            closureMethod ();
            Console.Read ();
        }

        // closure method
        private static void closureMethod ()
        {
            // outVariable and capturedVariable are external variables for anonymous methods
            // However, outVariable is an uncaught external variable, so it is uncaught because the variable is not referenced in the anonymous method
            string outVariable = "External Variable";

            // And capturedVariable is an external variable captured by anonymous method
            string captured Variable = "Capture Variable";
            ClosureDelegate closuredelegate = delegate
            {
                // localvariable is the local variable in the anonymous method
                string localvariable = "Anonymous method local variable";

                Console.WriteLine (capturedVariable + "" + localvariable);
            };

            // call delegate
            closureelegate ();
        }
    }
Copy code
Copy code
After a variable is captured, what is captured by the anonymous method is the real variable, not the value of the variable when the delegate instance is created, and the variable captured by the anonymous method will extend the life cycle (meaning that for a captured Variables, as long as there are any delegate instances that refer to it, it will always exist, and will not be garbage collected when the delegate instance is called). Let's take a specific example to see how anonymous methods extend the life cycle of variables:

Copy code
Copy code
class Program
    {
        // Define closure delegate
        delegate void ClosureDelegate ();

        static void Main (string [] args)
        {
            ClosureDelegate test = CreateDelegateInstance ();
            test ();
   
            Console.Read ();
        }

        // Closures extend the life cycle of variables
        private static ClosureDelegate CreateDelegateInstance ()
        {
            int count = 1;
  
            ClosureDelegate closuredelegate = delegate
            {
                Console.WriteLine (count);
                count ++;
            };

            // call delegate
            closureelegate ();
            return closuredelegate;
        }
}
Copy code
Copy code
The running result is:



The 1 in the first line is the result of calling the delegate instance internally in CreateDelegateInstance. First of all, you must think that count is allocated on the stack (because count is a value type). When the CreateDelegateInstance method is called, the value of count will also be destroyed. When the test () line of code is executed, the anonymous method will be called back to output the value of count at this time, because the count is destroyed, it should be reasonable to have an exception, but the result is 2, but the result is not wrong, according to the result If we go backwards, we can conclude that the second call to the delegate instance is still using the original count, but the reason why we think there will be an exception is thrown, mainly because we think that the count is allocated on the stack, however This is not the case. The count variable is not allocated on the stack. In fact, the compiler will create an additional class to accommodate the variable (the count variable is allocated on the heap at this time). The CreateDelegateInstance method has one of this class. Instance reference, so the variable count captured by the anonymous method at this time is a reference to it, not really At the same time, the anonymous method also extends the life cycle of the variable count, making it feel no longer like a local variable, but like a "global variable" (because the delegate instance called in the second time uses the same count) .

The variable captured by the anonymous method, the compiler will create an additional class to accommodate the variable. For this, you can view it through the IL disassembler. The following is a screenshot of the above program using the disassembler:

 



As can be seen from the screenshot above, there is no <> c_DisplayClass1 class defined in the source code, but this class is really created by the compiler for us to accommodate the capture variable count, and this class contains the CreateDelegateInstance method, from above The middle language code in the left half of the figure shows that the CreateDelegateInstance method defined in the source code has a reference to the <> c_DisplayClass1, and the count variable compiler used in the source code considers it to be a field in <> c_DisplayClass1.

4. Summary

 This topic mainly introduces the use of anonymous methods and anonymous methods to extend the life cycle of variables by capturing variables. I hope that through the introduction of this topic, you can have a comprehensive understanding of anonymous methods, and anonymous methods are also the basis of Lambda expressions. , Lambda expression is just a more concise way to implement anonymous methods in C # 3.0.

Related Article

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.