• About闭包


    using System;
    using System.Collections.Generic;
    using System.Collections;

    class Program
    {
        static void Main(string[] args)
        {
            //第一个例子
            //int counter = 0;
            //IEnumerable<int> values = Utilities.Generate(10, () => counter++);

            //Console.WriteLine("Current Counter: {0}", counter);
            //foreach (int num in values)
            //    Console.WriteLine(num);

            //Console.WriteLine("Current Counter: {0}", counter);

            //foreach (int num in values)
            //{
            //    Console.WriteLine(num);
            //}

            //Console.WriteLine("Current Counter: {0}", counter);
            //IEnumerator<int> obj = GetEnumerator();
            //foreach (var item in obj)
            //{
            //    Console.WriteLine(item);   
            //}        

            //第二个例子
            A a=new A();
            IEnumerable<int> arr = a.Fun();
            foreach (var tem in arr)
            {
                Console.WriteLine(tem);
            }
            foreach (var tem in arr)
            {
                Console.WriteLine(tem);
            }

            //第三个例子
            //foreach (var item in a)
            //{
            //    Console.WriteLine(item);
            //}
            //Console.WriteLine("-------------------------------");
            //foreach (var item in a)
            //{
            //    Console.WriteLine(item);
            //}
        }
    }

    class A : IEnumerable<int>
    {
        int count = 0;
        public IEnumerator<int> GetEnumerator()
        {
            for (int i = 0; i < 5; i++)
                yield return count++;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            for (int i = 0; i < 5; i++)
                yield return count++;

        }

        public IEnumerable<int> Fun()
        {
            for (int i = 0; i < 5; i++)
                yield return count++;
        }
    }

    class B : IEnumerable<int>
    {
        #region IEnumerable<int> 成员

        public IEnumerator<int> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerable 成员

        IEnumerator IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        #endregion
    }


    public static class Utilities
    {
        public static IEnumerable<T> Generate<T>(int num, Func<T> generator)
        {
            int index = 0;
            while (index++ < num)
                yield return generator();
        }
    }

    闭包的实现原理:

    在.NET 1.x时我们可能会写这样的代码:1

    public static void TestRequest(string url)
    {
        WebRequest request = HttpWebRequest.Create(url);
        object[] context = new object[] { url, request };
        request.BeginGetResponse(TestAsyncCallback, context);
    }

    public static void TestAsyncCallback(IAsyncResult ar)
    {
        object[] context = (object[])ar.AsyncState;
        string url = (string)context[0];
        WebRequest request = (WebRequest)context[1];

        using (WebResponse response = request.EndGetResponse(ar))
        {
            Console.WriteLine("{0}: {1}", url, response.ContentLength);
        }
    }我们需要自己维护一个object[]作为callback的参数,这样不仅是弱类型还很麻烦。好在.NET 2.x引入了匿名方法:

    public static void TestRequest(string url)
    {
        WebRequest request = HttpWebRequest.Create(url);
        request.BeginGetResponse(delegate(IAsyncResult ar)
        {
            using (WebResponse response = request.EndGetResponse(ar))
            {
                Console.WriteLine("{0}: {1}", url, response.ContentLength);
            }
        },
        null);
    }很方便吧!2 新定义的delegate可以直接用TestRequest里的变量,就在于生成了一个闭包。

    闭包(Closure)是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。3

    C#中闭包的实现
    从上边看来闭包与匿名方法有点关系,但.NET中本并没有什么匿名方法,我们还是用Reflector看下编译器到底生成了什么样的代码。这里注意要修改下Reflector的设置,View->Options->Disassembler->Optimization改为.Net 1.0 。

    public static void TestRequest(string url)
    {
        <>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
        CS$<>8__locals2.url = url;
        CS$<>8__locals2.request = WebRequest.Create(CS$<>8__locals2.url);
        CS$<>8__locals2.request.BeginGetResponse(new AsyncCallback(CS$<>8__locals2.<TestRequest>b__0), null);
    }
    [CompilerGenerated]
    private sealed class <>c__DisplayClass1
    {
        // Fields
        public WebRequest request;
        public string url;

        // Methods
        public void b__0(IAsyncResult ar)
        {
            using (WebResponse response = this.request.EndGetResponse(ar))
            {
                Console.WriteLine("{0}: {1}", this.url, response.ContentLength);
            }
        }
    }

    可见编译器至少做了两件事

    生成了一个类,包括匿名方法的方法体和所有引用的自由变量
    调用匿名方法的方法里的相关变量都被替换为生成类的字段,相关方法被替换为生成类的方法

  • 相关阅读:
    C#扩展方法学习
    如何用PS快速做出3D按钮效果的图片
    比较C#中几种常见的复制字节数组方法的效率[转]
    GUID的学习
    委托与事件的区别
    利用Marshal.AllocHGlobal申请非托管内存,unsafe代码
    JAVASE(十三) 异常处理
    JAVASE(十二) Java常用类: 包装类、String类、StringBuffer类、时间日期API、其他类
    JAVASE(十一) 高级类特性: abstract 、模板模式、interface、内部类、枚举、注解
    面试题: SpringBoot 的自启动原理
  • 原文地址:https://www.cnblogs.com/mxw09/p/1787594.html
Copyright © 2020-2023  润新知