C#函数式编程中的惰性求值详解

惰性求值

在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术。首先需要说明的是C#语言小部分采用了非严格求值策略,大部分还是严格求值策略。首先我们先演示非严格求值策略的情况,我们先在控制台项目中写一个DoOneThing方法。

然后在Main方法中写入下面这串代码:

然后我们运行程序,会发现DoOneThing方法并没有执行。当然这看起来也很正常,因为这是或,并且第一个已经是true了。整个表达式就是true了,自然第二个就无需求值了。但是这恰恰就是非严格求值的策略,如果是严格求值策略的话整个表达式都会计算。接着就是严格求值策略的情况了,这个相信很多人都会立马明白,首先我们需要再写一个DoSomeThing方法:

接着修改Main方法:

执行之后我们可以看到如下的结果:

但是我们可以清楚的看到a的值是false,根本不会使用b值,但是传递参数的时候已经将DoOneThing方法执行并赋值给b,假设这个方法是一个非常耗时的操作。那么我们就会白白浪费掉这段时间,最后求得的值也没有使用的到。而这正是严格求值策略,而今天的主要目标就是改变这种情况,能够在我们确定需要某个值的时候才计算。下面我们就可以开始改造这个方法,让其能够支持惰性求值。首先我们修改DoSomeThing方法:

这里我们将参数类型都改成了函数,这样将要传递进来的参数都改变成函数。只有在我们需要的时候才执行求值,否则是不会运行的,对应的Main方法中我们需要按照如下方式修改:

这里我们并不需要把DoOneThing方法的返回类型改掉,如果这样的话。在现有项目上使用函数式编程就会显得太麻烦了。这里我们仅仅只需要利用匿名函数就可以办到了,下面我们可以看最后的执行效果:

DoOneThing方法并没有执行,因为DoSomeThing中根本没有确定使用这个变量,这样我们就能够节省下这部分计算的时间,但是事实上我们还没有结束,实际的开发中我们可能需要多次使用这个值,比如下面我们修改DoSomeThing方法:

并且在Main方法中调用DoSomeThing方法时将第一个参数改成true,然后执行我们就可以看到下面的输出结果:

DoOneThing方法被执行了两次,当然我们可以利用局部变量保存,可能你会这么写:

如果这么写,那么我们的惰性求值就没有任何意义了,因为一进入这个方法就执行了这个方法,跟传递参数时直接将运算后的结果赋值给b没有任何区别了。当然也有其他一些技巧可以避免,但是这些技巧可不是下面要讲的内容,我们可以将其封装起来,比如我们可以写个LazyS<T>类:

我们可以看到在构造方法部分我们将对应的函数作为参数接收并保存到function中,只有再调用Value时候会执行该函数并将值保存,并且在下次调用时,如果已经求值过则直接返回缓存过的值,这样就能够避免重复的执行了,对应的我们还要修改DoSomeThing方法和Main方法:

最终执行后我们可以看到仅执行了一次DoOneThing方法:

一些读者可能为问为什么类名不要Lazy而是加个S,因为.net中已经为我们包含了Lazy<T>类,相信很多人基本上从没有用过。只知道Func和Action的存在,下面我们修改我们的代码直接利用自带的:

最终的结果之前的是一摸一样,当然系统自带的Lazy功能更多,并且支持多线程。

就到这里为止吧,周五了大家已经按耐不住了,写了太多可能就没有心思往下看了,所以将这些全部一个一个拆分开来细讲。

(0)

相关推荐

  • C#利用Random得随机数求均值、方差、正态分布的方法

    本文实例讲述了C#利用Random得随机数求均值.方差.正态分布的方法.分享给大家供大家参考.具体如下: 最近在做中小学试卷分析系统,其中数据的分析让自己很头疼,整个系统采用B/S架构.在分析试卷难度梯度的时候需要用到正态分布,自己做了一些,也查阅了一些资料,终于掌握了将一组数据分析检验,最后生成正态分布. (1)利用随机函数rand()生成(0,1)区间的100个均匀分布随机数: (2)计算这100个均匀分布随机数的均值和方差, (3)将这100个均匀分布的随机数,及其均值和方差保存到文本文件

  • C#求n个数中最大值和最小值的方法

    本文实例讲述了C#求n个数中最大值和最小值的方法.分享给大家供大家参考.具体实现方法如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { Console.WriteLine("输入十个数: "); /

  • python求众数问题实例

    本文实例讲述了python求众数问题的方法,是一个比较典型的应用.分享给大家供大家参考.具体如下: 问题描述: 多重集中重数最大的元素称为众数...就是一个可以有重复元素的集合,在这个集合中重复的次数最多的那个数就叫它的众数... 如S = [1,2,2,2,3,5] 重数是2,其重数为3 实例代码如下: list_num = [] list_num_count = 0 dict_num ={} #从文件读入,文件第一行为集合中元素的个数,以后每一行为一个元素 list_num_count =

  • C#实现求一组数据众数的方法

    本文实例讲述了C#实现求一组数据众数的方法.分享给大家供大家参考.具体如下: 1.算法描述 1)输入合法性检验(输入不能为空) 2)制作数组副本,后面的操作将不修改数组本身,只对副本进行操作 3)数组排序(把相等的数都凑到一"堆儿") 4)统计不同的元素数(统计"堆儿"数,以确定步骤5中要使用的数组大小) 5)统计各个元素数量(统计每"堆儿"的大小,并存入数组) 6)按元素在原数组内数量降序排列,数量相等的元素则按大小升序排列 7)统计众数数量(

  • C#中 城市线路图的纯算法以及附带求极权值

    之前看了很多关于图的遍历的代码 今天我用了常用的数据结构写出来 纯属于算法 性方面还有待提高 时间复杂度最坏情况下O(2^n)  最优:O(n^2) 线路图为双向 带有权值  比如A-B距离是5000km 那么B-A有可能不是5000km 所以我在LoadData方法时候没做交换变量直接存放在集合里面 以起点递归查找下一连接点并返回当作起点节点查找      代码虽然有些乱 本想调整 ! 复制代码 代码如下: static List<string[]> maindata = null;    

  • c#求两个数中最大值的方法

    1.三元运算符: 复制代码 代码如下: class Program    {        static void Main(string[] args)        {          int max= NumMAX(10,15);            Console.WriteLine("最大数:{0}",max);            Console.ReadKey();        }   /// <summary>        /// 两个数中最大的值

  • C#函数式编程中的惰性求值详解

    惰性求值 在开始介绍今天要讲的知识之前,我们想要理解严格求值策略和非严格求值策略之间的区别,这样我们才能够深有体会的明白为什么需要利用这个技术.首先需要说明的是C#语言小部分采用了非严格求值策略,大部分还是严格求值策略.首先我们先演示非严格求值策略的情况,我们先在控制台项目中写一个DoOneThing方法. 然后在Main方法中写入下面这串代码: 然后我们运行程序,会发现DoOneThing方法并没有执行.当然这看起来也很正常,因为这是或,并且第一个已经是true了.整个表达式就是true了,自

  • C#函数式编程中的标准高阶函数详解

    何为高阶函数 大家可能对这个名词并不熟悉,但是这个名词所表达的事物却是我们经常使用到的.只要我们的函数的参数能够接收函数,或者函数能够返回函数,当然动态生成的也包括在内.那么我们就将这类函数叫做高阶函数.但是今天我们的标题并不是高阶函数,而是标准高阶函数,既然加上了这个标准,就意味着在函数式编程中有一套标准的函数,便于我们每次调用.而今天我们将会介绍三个标准函数,分别为Map.Filter.Fold.  Map 这个函数的作用就是将列表中的每项从A类型转换到B类型,并形成一个新的类型.下面我们可

  • Java栈的运用之中缀表达式求值详解

    目录 栈运用题:中缀表达式求值 题目详情 解题思路 实现代码 栈运用题:中缀表达式求值 题目详情 给定一个表达式,其中运算符仅包含 +,-,*,/(加 减 乘 整除),可能包含括号,请你求出表达式的最终值. 注意: 数据保证给定的表达式合法. 题目保证符号 - 只作为减号出现,不会作为负号出现,例如,-1+2,(2+2)*(-(1+1)+2) 之类表达式均不会出现. 题目保证表达式中所有数字均为正整数. 题目保证表达式在中间计算过程以及结果中,均不超过 231−1. 题目中的整除是指向 0 取整

  • Java编程中的HashSet和BitSet详解

    Java编程中的HashSet和BitSet详解 我在Apache的开发邮件列表中发现一件很有趣的事,Apache Commons包的ArrayUtils类的removeElements方法,原先使用的HashSet现在换成了BitSet. HashSet<Integer> toRemove = new HashSet<Integer>(); for (Map.Entry<Character, MutableInt> e : occurrences.entrySet()

  • python函数式编程学习之yield表达式形式详解

    前言 yield的英文单词意思是生产,刚接触Python的时候感到非常困惑,一直没弄明白yield的用法.最近又重新学习了下,所以整理了下面这篇文章,供自己和大家学习参考,下面话不多说了,来一起看看详细的介绍吧. 先来看一个例子 def foo(): print("starting...") while True: res = yield print("res:",res) g = foo() next(g) 在上面的例子里,因为foo函数中有yield关键字,所以

  • Swift编程中的一些类型转换方法详解

    验证一个实例的类型'类型转换'在 Swift 语言编程中.它是用来检查实例类型是否属于特定超类或子类或其自己的层次结构定义. Swift 类型转换提供两个操作符:"is" 检查值的类型和 'as' 将类型值转换为不同的类型值. 类型转换还检查实例类型是否符合特定的协议一致性标准. 定义一个类层次结构 类型转换用于检查实例的类型或者它属于特定类型.此外,检查类和它的子类层次结构来检查并转换这些实例,使之作为一个相同的层次结构. 复制代码 代码如下: class Subjects {   

  • Android编程中光线传感器的调用方法详解

    本文实例讲述了Android编程中光线传感器的调用方法.分享给大家供大家参考,具体如下: 1.activity如果要使用传感器,就必须实现SensorEventListener接口 2.得到传感器管理对象(sensormanager) 3.使用sensormanager.registerlistener 方法注册指定的传感器 4.在sensoreventlistener 接口中的onsensorchanged和onaccuracychanged方法中完成其他具体工作 public class T

  • Android编程中的消息机制实例详解

    本文实例讲述了Android编程中的消息机制.分享给大家供大家参考,具体如下: 在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListener { private TextView stateText; private Button btn; @Override public void onCreate(Bundle savedInstanceState)

  • php in_array() 检查数组中是否存在某个值详解

    php in_array() 检查数组中是否存在某个值 in_array检查数组中是否存在某个值 基本语法: bool in_array(mixed $needle,array $haystack,bool $strict=FALSE) 在 haystack 中搜索 needle 参数介绍 参数 描述 needle 必需.规定要在数组搜索的值.如果是字符串,则比较是区分大小写的. haystack 必需.规定要搜索的数组. strict 可选.如果设置该参数为 true,则 in_array()

  • Android编程中context及全局变量实例详解

    本文实例讲述了Android编程中context及全局变量的用法.分享给大家供大家参考,具体如下: 今天在研究context的时候,对application和activity context有了一定的了解,下面是从网上复制过来的资料 Application context和Activity context的区别: 这是两种不同的context,也是最常见的两种.第一种中context的生命周期与Application的生命周期相关的,context随着Application的销毁而销毁,伴随ap

随机推荐