Explore function creation and closure in c,

Source: Internet
Author: User

Explore function creation and closure in c,

Reading directory:

Dynamic Function Creation

Most of you have used it more or less. Review the evolution of dynamic function creation in c:

C #1.0:

  public delegate string DynamicFunction(string name);  public static DynamicFunction GetDynamicFunction()  {      return GetName;  }  static string GetName(string name)  {      return name;  }  var result = GetDynamicFunction()("mushroom");

3.0 is it complicated and lagging behind. When I just learned to delegate, I understood the delegate as a function pointer. Let's also look at the implementation with the function pointer:

char GetName(char p);typedef char (*DynamicFunction)(char p);DynamicFunction GetDynamicFunction(){    return GetName;}char GetName(char p){    return p;};char result = GetDynamicFunction()('m');

In comparison, c #1.0 is almost the same (reference/pointer difference). After all, it is in the same family.

In C #2.0, add an anonymous function:

      public delegate string DynamicFunction(string name);      DynamicFunction result2 = delegate(string name)      {          return name;      };

In C #3.0, add a Lambda expression and turn around in a gorgeous way:

 public static Func<string, string> GetDynamicFunction() {        return name => name; } var result = GetDynamicFunction()("mushroom");
Limitations of anonymous Functions

Although adding Lambda expressions has greatly simplified our workload. But there are indeed some shortcomings:

var result = name => name;

These errors are reported during compilation. Because c # is a strong-type language, the var syntax sugar is provided to save the workload of declaring and determining the type. The compiler must be able to completely deduce the types of parameters during compilation. The name parameter type in the Code cannot be inferred during compilation.

var result = (string name) => name;Func<string, string> result2 = (string name) => name;Expression<Func<string, string>> result3 = (string name) => name;

The name type is directly declared above. Unfortunately, this is also an error. The answer is provided in the Code. The compiler cannot infer whether the right Expression belongs to the Func <string, string> type or Expression <Func <string, string> type.

 dynamic result = name => name; dynamic result1 = (Func<string,string>)(name => name);

If dynamic is used, the compiler cannot tell whether a delegate is on the right. We can display the conversion.

Func<string, string> function = name => name;DynamicFunction df = function;

A func delegate is defined here. Although the parameter and return value types are the same as those of the DynamicFunction delegate, an error still occurs during compilation: the Func <string, string> to DynamicFunction cannot be implicitly converted, the two types are incompatible.

Understand the closure in c #

The dynamic function creation involves closures. There is a lot of information about the concept of closure. The theoretical part will not be repeated here. Let's take a look at the closure in c # code:

Func <int> A = () => {var age = 18; return () => // function B {return age ;};}; var result = ()();

The above is the closure, which can be understood:Cross-scope access to function variables,There are also behaviors with data.
C # There are three types of variable scopes: class variables, instance variables, and function variables. Variables in the sub-scope accessing the parent scope (that is, accessing the instance/class variables in the function) are taken for granted by us and conform to our programming habits.
In this example, anonymous function B is the variable age that can access upper-layer function. For the compiler, function A is the parent scope of function B, so the age variable accessed by function B to the parent scope is compliant with the specification.

       int age = 16;        void Display()        {            Console.WriteLine(age);              int age = 18;            Console.WriteLine(age);        } 

In the above compilation, an error is reported and is not declared for use. After the compiler checks that the age is declared in the function, the scope will overwrite the age of the parent scope (like JS undefined ).

        Func<int> C = () =>         {             var age = 19;             return age;         };

If the same-Level Function C is declared above, function A cannot access the age variable in Function C. In short, variables in other functions cannot be accessed across scopes. Then how does the compiler implement the closure mechanism?

For example, the answer is to upgrade the scope of A function to an instance class scope. During code compilation, the compiler automatically generates an anonymous Class x when checking that function B uses the variable in function, the age variable in the original function A is upgraded to the field of the x class (that is, the instance variable), and the function is upgraded to the instance function of the anonymous class x. The following is the code generated by the compiler (simplified ):

Class Program1 {static Func <int> CachedAnonymousMethodDelegate2; static void Main (string [] args) {Func <int> func = new Func <int> (Program1. B); int num = func ();} static Func <int> B () {DisplayClass cl = new DisplayClass (); cl. age = 18; return new Func <int> (cl. a) ;}} sealed class DisplayClass {public int age; public int A () {return this. age ;}}View Code

Let's look at a complex example:

    static Func<int, int> GetClosureFunction()    {        int val = 10;        Func<int, int> interAdd = x => x + val;        Console.WriteLine(interAdd(10));        val = 30;        Console.WriteLine(interAdd(10));        return interAdd;    }  Console.WriteLine(GetClosureFunction()(30));

The output values are 20, 40, and 60. When we see that the val variable in this function is passed through the closure, we know that val is not just a variable in the function. We have previously analyzed how the compiler generates code, knowing that val is an instance variable of an anonymous class, And interAdd is an instance function of an anonymous class. Therefore, no matter how many layers are passed by val, its value is always maintained until it leaves the (chained) scope.

There are many discussions about closures in js. Likewise, we can compare and understand the following:

function A() {    var age = 18;    return function () {        return age;    }}A()();
Advantages of closures
  • Variable Protection. If you want to expose a variable value, but you are afraid that the declared class or instance variable will be contaminated by other functions, you can design a closure and use it only through function calls.
  • Logical continuity and variable persistence. A () is to execute part of the logic. A () only follows the () logic. During the logical context, variables are always maintained and can be used at will.

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.