Understanding closures in C #

Source: Internet
Author: User

1, the meaning of closure package

First, closures are not a concept for a particular language, but rather a generic concept. In addition to the various languages that support functional programming, we are exposed to it. Some languages that do not support functional programming can also support closures (such as anonymous inner classes prior to java8).

As seen in the definition of closures, the individual feels more clearly in the book "JavaScript Advanced Programming". It is defined as follows:

closures are functions that have access to variables in another function scope.

Note that the word closure itself refers to a function. A common way to create this particular function is to create another function in one function.

2. Use closures in C # (example selected from C # functional programming)

Let's take a simple example to understand C # closures

class Program{    static void Main(string[] args)    {        Console.WriteLine(GetClosureFunction()(30));    }    static Func<int, int> GetClosureFunction()    {        int val = 10;        Func<int, int> internalAdd = x => x + val;        Console.WriteLine(internalAdd(10));        val = 30;        Console.WriteLine(internalAdd(10));        return internalAdd;    }}

The execution flow of the above code is that the main function calls the Getclosurefunction function, Getclosurefunction returns the delegate Internaladd and is executed immediately.

The output results are 20, 40, 60, respectively.

Corresponds to the concept of closure proposed at the outset. This delegate internaladd is a closure that references the variable Val in the scope of the external function getclosurefunction.

Note : Internaladd has no relation to the definition of the return value and closure. Even if it is not returned to the outside, it is still a closed packet.

3. Understanding the implementation principle of closures

Let's take a look at the execution of this piece of code. At the outset, the function getclosurefunction defines a local variable val and a delegate internaladd created with LAMDBA syntax sugar.

First execution Delegate Internaladd 10 + 10 Output 20

The local variable value val that is referenced by the Internaladd is then changed, and the delegate is executed again with the same parameters, outputting 40. It is obvious that the change of local variable affects the execution result of the delegate.

Getclosurefunction returns the Internaladd to the outside, with 30 as the parameter, the result of the execution is 60, and the last value of the Val local variable 30 is the same.

Val as a local variable. Its life cycle should have ended when the getclosurefunction was executed. Why does it have an impact on the outcome?

We can look at what the compiler does for us through anti-compilation.

To increase readability, the following code modifies the name generated by the compiler and properly organizes the code.

class Program{    sealed class DisplayClass    {        public int val;        public int AnonymousFunction(int x)        {            return x + this.val;        }    }    static void Main(string[] args)    {        Console.WriteLine(GetClosureFunction()(30));    }    static Func<int, int> GetClosureFunction()    {        DisplayClass displayClass = new DisplayClass();        displayClass.val = 10;        Func<int, int> internalAdd = displayClass.AnonymousFunction;        Console.WriteLine(internalAdd(10));        displayClass.val = 30;        Console.WriteLine(internalAdd(10));        return internalAdd;    }}

The compiler creates an anonymous class (if you do not need to create a closure, the anonymous function will only live in the same class as Getclosurefunction, and the delegate instance will be cached, see CLR via C # version 362, page fourth), and creates an instance of it in Getclosurefunction. A local variable is actually present as a field in an anonymous class.

4. C#7 optimization of closures for non-return values

If you write the code for section two in vs2017. You will get a hint asking if you want to take the lambda expression (anonymous function) to the local function. The local function is a new syntax provided by C#7. So what's the difference between using a local function to implement closures?

If the code is the same as the second section, change it to a local function and look at the IL code. There is actually no change.

class Program{    static void Main(string[] args)    {        Console.WriteLine(GetClosureFunction()(30));    }    static Func<int, int> GetClosureFunction()    {        int val = 10;        int InternalAdd(int x) => x + val;        Console.WriteLine(InternalAdd(10));        val = 30;        Console.WriteLine(InternalAdd(10));        return InternalAdd;    }}

But when Internaladd does not need to be returned , the result is different.

The following is a look at the anonymous function and the local function to create a closure that is not the return value when the demo code and the compiled anti-compilation code.

anonymous functions

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

Collated anti-compilation code

sealed class DisplayClass{    public int val;    public int AnonymousFunction(int x)    {        return x + this.val;    }}static void GetClosureFunction(){    DisplayClass displayClass = new DisplayClass();    displayClass.val = 10;    Func<int, int> internalAdd = displayClass.AnonymousFunction;    Console.WriteLine(internalAdd(10));    displayClass.val = 30;    Console.WriteLine(internalAdd(10));}

Local functions

class Program{    static void Main(string[] args)    {    }    static void GetClosureFunction()    {        int val = 10;        int InternalAdd(int x) => x + val;        Console.WriteLine(InternalAdd(10));        val = 30;        Console.WriteLine(InternalAdd(10));    }}

Collated anti-compilation code

// 变化点1:由原来的class改为了structstruct DisplayClass{    public int val;    public int AnonymousFunction(int x)    {        return x + this.val;    }}static void GetClosureFunction(){    DisplayClass displayClass = new DisplayClass();    displayClass.val = 10;    // 变化点2:不再构建委托实例,直接调用值类型的实例方法    Console.WriteLine(displayClass.AnonymousFunction(10));    displayClass.val = 30;    Console.WriteLine(displayClass.AnonymousFunction(10));}

This two-point change to some extent can bring performance improvements, so in the official recommendation, if the use of delegates is not necessary, it is more recommended to use local functions rather than anonymous functions.

If there is a problem with the content described in this blog, we hope that we can make valuable comments. Keep blogging, starting with this one.

Understanding closures in C #

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.