尽早执行与延迟执行的区别
前言
声明式的代码 (declarative code) 的重点在于把执行的结果定义出来,而 命令式代码(imperative code) 则重在详细描述实现该结果所需的步骤。这两种代码都可以写出正确的程序,但如果混起来用,那么程序的行为就有可能错乱。
实例
运行命分令式的代码时,必须把方法所需的参数计算好,然后才能调用该方法,例如下面这行代码就是用命令式风格写成的,必须依次执行 Method1(),Method2(),Method3() 这三个步骤,然后才能把每步所得的结果当成参数来调用 Dostuft 方法。
var answer =Dostuff(Method1(),Method2(),Method3());
程序的运行顺序是:
- 调用 Method1 ,以求出 DoStuff() 的第一个参数。
- 调用 Method2 ,以求出 DoStuff() 的第二个参数。
- 调用 Method3 ,以求出 DoStuff() 的第三个参数。
- 用计算好的这三个参数来调用 DoStuff 。
对于这种写法大家应该比较熟悉。在执行方法之前,系统必须把所有的参数都计算出来,而且会把计算时所用的数据发送过去。这样写出来的算法实际上是一系列步骤 ,必须按顺序执行这些步骤,才能得出结果。
另一种写法是采用lambda表达式及查询表达式来实现,这样写出来的算法其执行方式与命令式的代码不同。这种延迟执行(deferred executio)的做法其效果可能令你感到意外。下面这行代码的功能与早前那行代码似乎差不多,但稍后你就会看到,它们之间其实有着很大的区别:
var awswer = DoStuff(()=>Method1(), ()=>Method2(), ()=>Method3());
这次的运行情况是:
- 调用Dostuff(), 并且把那三条 lambda 表达式传给它,这些表达式本身可以分别调用 Method1(),Method2(),Method3()。
- 在 Dostuff 内部, 只有当程序真正需要用到Method1的执行结果时,才会调用 该方法。
- 在 Dostuff 内部, 只有当程序真正需要用到Method2的执行结果时,才会调用 该方法。
- 在 Dostuff 内部, 只有当程序真正需要用到Method3的执行结果时,才会调用 该方法。
- Method1(),Method2(),Method3() 这三个方法可以按照任意顺序来调用,而且每个方法的调用次数也不一定(甚至有可能根本就不调用)。
总结
总之,只有当程序确实需要用到某个方法的执行结果时,才会去调用这个方法。这是声明式写法与命令式写法之间的重要区别。如果把两种方法混起来用,那么程序可能就会出现严重的问题。