条件表达式的短路求值与函数的延迟求值

延迟求值是 .NET的一个很重要的特性,在LISP语言,这个特性是依靠宏来完成的,在C,C++,可以通过函数指针来完成,而在.NET,它是靠委托来完成的。如果不明白什么是延迟求值的同学,我们先看看下面的一段代码:

      static void TestDelayFunction()
        {
            TestDelayFunton1(true,trueFun3);
        }

        static void TestDelayFunton1(bool flag , Func<bool> fun  )
        {
            if(flag)
               fun();
        }

在方法  TestDelayFunton1 中,函数型参数 fun 是否求值,取决于第一个参数  flag,如果它的值为false,那么函数 fun 是永远都不会被求值的,所以,这里函数 fun的求值被推迟到了方法TestDelayFunton1 的内部,而不是在参数计算的时候。

延迟求值很有用,它可以避免我们无谓的计算,比如上面的例子,这样可以节省计算成本,假如 fun的求值很耗时的话。

我们注意这一段代码:

if(flag)

   fun();

其实它等价于一个逻辑表达式:

bool result= flag && fun();

在这个表达式中,fun() 函数是否求值,取决于变量 flag,这个功能叫做“短路”判断,“条件短路”功能正好实现了我们的“延迟求值”的功能,因此,我们可以得到如下推论:

任何时候一个函数fun如果需要延迟求值,那么都可以表示成 一个条件表达式:

(Test() && fun())

所以,前面的2个函数,本质上可以改写成下面的一个函数:

      static void TestDelayFunton2(bool flag)
        {
            bool result = flag && trueFun3();
        }

它将  TestDelayFunton1(true,trueFun3); 的形式调用,转换成了上面的一个函数调用。

当然,要让这种调用变得可用,我们还需要解决一个问题,就是函数 fun()的类型并不是 bool类型,这个问题处理很简单,将函数再包装下即可:

bool WarpFunction()
{
  fun();
  return true;
}

之后的调用将是这个样子的:

(Test() && WarpFunction())

对于本例,它其实等价于:

(flag && trueFun3())

如果是“聪明”的编译器,它是可以完成上面的转换的,下面给出一个完整的代码图片,这样你能够看得更清楚:

上面被标记的部分的2个函数,等价于下面这一个函数。

如果你对上面的这个过程还是不太明白,那么我们看看下面这个例子:

 static bool trueFun1()
        {
            Console.WriteLine("call fun 1");
            return true;
        }

        static bool falseFun2()
        {
            Console.WriteLine("call fun 2");
            return false;
        }

        static bool trueFun3()
        {
            Console.WriteLine("call fun 3");
            return true;
        }

执行下面的代码,trueFun3都会被执行么?

if (trueFun1() && falseFun2() && (trueFun3()))
{ 

}
 Console.WriteLine();
if (trueFun1() || falseFun2() || trueFun3())
{

}

假如你非常理解C#的“条件短路”特性,相信答案很快就出来了。

阅读完本文,你可能会问如此奇淫巧技,有何作用?

如果你深入研究.NET的委托,就会明白委托调用其实是将一个函数用对象进行包装,.NET自动为你生成了好多代码,性能上比如有所损耗,加入你在某些地方需要性能极致的代码,那么本文这个技巧一定可以帮助你,加入你还能够写出一个这种转换的编译器来,恭喜你,未来的大神就是你了!

时间: 2024-10-07 05:02:10

条件表达式的短路求值与函数的延迟求值的相关文章

重构手法之简化条件表达式【1】

返回总目录 本小节目录 Decompose Conditional(分解条件表达式) Consolidate Conditional Expression(合并条件表达式) 1Decompose Conditional(分解条件表达式) 概要 你有一个复杂的条件(if-else if-else)语句. 从if.else if.else三个段落中分别提炼出独立函数. 动机 复杂的条件逻辑往往会导致程序复杂度上升.编写代码来检查不同的条件分支.根据不同的分支做不同的事往往又会导致函数过长. 将条件表

【基础】函数的声明&amp;返回值

以加减乘除运算为例 /* 函数的一般形式: 类型标示符 函数名(形式参数,形式参数...){ 函数体 } 类型表示符 为 该函数返回值的类型 不返回任何值的函数,返回值类型可以用void表示 void 函数名(){ } */ /* 函数的声明及调用: 引用空间: 函数名(形式参数,形式参数...);//声明函数 主函数(){ 函数名(实际参数,实际参数...);//在主函数中调用函数 } 函数名(形式参数,形式参数...) { 函数体 }//声明函数 函数声明时可以省略变量名 int Demo(

c指针 --笔记2返回指针值的函数

返回指针值的函数 一般带回指针值的函数,定义形式为: int *a (int x, int y); 看这个经典案例: #include <stdio.h> int main(int argc, char const *argv[]) { double score[][4] = {{60.0, 70.0, 80.5, 20.1}, {60.0, 70.0, 80.5, 21.1}, {60.0, 70.0, 80.5, 22.1}}; double *search(double(*pointer

(华为机试)双向链表实现字符串条件表达式的求值

描述: 给定一个以字符串形式表示的算术表达式,计算该表达式的值. 表达式支持如下运算:"+.-.*./",其中"*"和"/"的优先级要高于"+"和"-": 不需要考虑括号,且表达式之间没有空格: 例如:对于表达式"3-2+15*2",该表达式值为31. 运行时间限制: 60 Sec 内存限制: 256 MByte 输入: 加减乘除四则运算表达式,长度不超过1024字节,运算式中不含有括号

Oracle函数-单行函数-转换函数、条件表达式

单行函数 ============================================================ 特点: 每行返回一个结果,输入输出存在一一对应的关系 能嵌套使用 ,一个函数的输出能做另外一个函数的输入 如:select lowner(upper('aa')) from dual; 传入的变量可以是列的值,也可以是表达式. 如 select lower(ename) from emp; ======================================

Makefile 中条件表达式 以及函数

Makefile中条件表达式的语法为: <conditional-directive> <text-if-true> endif 或者 <conditional-directive> <text-if-true> else <text-if-false> endif <conditional-directive> 表示条件关键字: 关键字    说明 ifeq ifeq (arg1,arg2)       比较参数arg1和arg2的

从头认识Spring-1.15 对SpEl的值的操作(3)-逻辑运算以及条件表达式

这一章节我们来讨论一下对SpEl的逻辑运算以及条件表达式. 1.domain 烤炉类:(修改了toString方法,因为配置文件的表达式需要只返回跟Bean的id相同的name的属性值) package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_18; public class Oven { private String name = ""; private double size = 0; private boolean

编程题:返回指针值的函数,求两个数中较大的数。

#include<stdio.h> int *max(int *x,int *y) { int *q; if(*x>*y)  q=x; else  q=y; return q; } void main() { int a,b,*p; scanf("%d,%d",&a,&b); p=max(&a,&b); printf("%d,%d,max is %d\n",a,b,*p); } 编程题:返回指针值的函数,求两个数中较

Excel查询序列所对应的值-vLoopup函数,求比例分子改变但分母不变

其中G列sales_num_ratio = E2/L2 1. 在G2输入函数:=E2/VLOOKUP(C2,$K$2:$M$20,2,0),分母的函数固定不变($符号的作用) 2. 下拉填充,ok 参考: Excel如何查询序列所对应的值 http://jingyan.baidu.com/article/fb48e8be441e186e632e1473.html Excel查询序列所对应的值-vLoopup函数,求比例分子改变但分母不变