一个用来计算文本大小的方法(以及再一次对闭包的解释)

来源:互联网 发布:python 日期月份加减 编辑:程序博客网 时间:2024/06/07 07:48

闭包 与Lambda

先看一下这个方法:

 private static string FormatBytes(long bytes)        {            string[] magnitudes = new string[] { "GB", "MB", "KB", "Bytes" };            long max =(long)Math.Pow(1024, magnitudes.Length);            return string.Format("{1:##.##} {0}",                magnitudes.FirstOrDefault(                    magnitude =>                        bytes > (max /= 1024)) ?? "0 Bytes",                (decimal)bytes / (decimal)max).Trim();        }

这个方法可以用来计算一个网页HTML内容的长度的,比如我们使用下面这样的方式:

 WebRequest webRequest =WebRequest.Create(url); WebResponse response =webRequest.GetResponse(); Console.Write("....."); using (StreamReader reader =new StreamReader(response.GetResponseStream()))    {      string text =reader.ReadToEnd();      Console.WriteLine(FormatBytes(text.Length));    }

用这个方法可以获取网站请求的一个Response,然后从流中读取string文本的长度,然后可以用FormatBytes方法来得到该文本的长度,本文主要研究上面那个计算文本长度并转化为文件大小的方法FormatBytes():
magnitudes :该方法首先定义一个字符串数组,用于后面的计算。
max :得到该数组的1024的字符串长度数的幂,在这个例子中,就是1024的4次方。
③根据该方法的一个传入参数(该例中就是获取网页HTML文本的大小)bytes,以及max这两个变量,传入扩展方法string.FirstOrDefault中,此时,FirstOrDefault方法中的Lambda表达式形成了一个闭包:有兴趣的同学可以Reflector一下。这两个变量由于闭包的形成,在编译器生成的代码中已经被一个编译器生成的类(类似于<>c_DisplayClass1之类的东西,顺便说明一下,C#的编译器会帮助我们做很多事,比如异步Async和await生成的状态机,还有迭代器,所有这些由C#编译器生成的类,都是由<>这样的尖括号前缀表明的。)的字段所取代。也就是说,本来这两个变量的作用域在方法内部,编译器为了能够在方法的栈帧销毁后继续使用这两个变量(为了Lambda表达式,更准确的说,为了Lambda表达式的延迟执行),将这两个局部(本地)变量的级别提升为类字段的级别。
接着来说string.FirstOrDefault,string类型实现了IEnumerable接口,所以能使用IEnumerable上面的扩展方法,FirstOrDefault内接收一个Func<string,bool>的predicate(谓词),在这个方法中,该predicate为:

magnitude =>bytes > (max /= 1024)) 

由于Func<string,bool>返回的是一个string,所以该扩展方法会立即执行。该扩展方法会使用这个predicate来遍历magnitudes,每遍历一次,max都要除以1024(max /= 1024),直到返回true。当然,如果找不到这个值,会返回一个默认值,该默认值根据不同类型返回不同的默认值。

原创粉丝点击