提起函数式编程,大家一定想到的是语法高度灵活和动态的LISP,Haskell这样古老的函数式语言,往近了说ruby,javascript,F#也是函数式编程的流行语言。然而自从.net支持了lambda表达式,C#虽然作为一种指令式程序设计语言,在函数式编程方面也毫不逊色。我们在使用c#编写代码的过程中,有意无意的都会使用高阶函数,组合函数,纯函数缓存等思想,连表达式树这样的idea也来自函数式编程思想。所以接下来我们把常用的函数式编程场景做个总结,有利于我们在程序设计过程中灵活应用这些技术,拓展我们的设计思路和提高代码质量。
一、高阶函数
高阶函数通俗的来讲:某个函数中使用了函数作为参数,这样的函数就称为高阶函数。根据这样的定义,.net中大量使用的LINQ表达式,Where,Select,SelectMany,First等方法都属于高阶函数,那么我们在自己写代码的时候什么时候会用到这种设计?
举例:设计一个计算物业费的函数,var fee=square*price, 而面积(square)根据物业性质的不同,计算方式也不同。民用住宅,商业住宅等需要乘以不同的系数,根据这样的需求我们试着设计下面的函数:
民用住宅面积:
public Func SquareForCivil()
{
return (width,hight)=>width*hight;
}
商业住宅面积:
public Func SquareForBusiness()
{
return (width, hight) => width * hight*1.2m;
}
这些函数都有共同的签名:Func,所以我们可以利用这个函数签名设计出计算物业费的函数:
public decimal PropertyFee(decimal price,int width,int hight, Func square)
{
return price*square(width, hight);
}
是不是很easy,写个测试看看
[Test]
public void Should_calculate_propertyFee_for_two_area()
{
//Arrange
var calculator = new PropertyFeeCalculator();
//Act
var feeForBusiness= calculator.PropertyFee(2m,2, 2, calculator.SquareForBusiness());
var feeForCivil = calculator.PropertyFee(1m, 2, 2, calculator.SquareForCivil());
//Assert
feeForBusiness.Should().Be(9.6m);
feeForCivil.Should().Be(4m);
}
二、惰性求值
C#在执行过程使用严格求值策略,所谓严格求值是指参数在传递给函数之前求值。这个解释是不是还是有点不够清楚?我们看个场景:有一个任务需要执行,要求当前内存使用率小于80%,并且上一步计算的结果
我们可以很快写出符合这个要求的C#代码:
public double MemoryUtilization()
{
//计算目前内存使用率
var pcInfo = new ComputerInfo();
var usedMem = pcInfo.TotalPhysicalMemory - pcInfo.AvailablePhysicalMemory;
return (double)(usedMem / Convert.ToDecimal(pcInfo.TotalPhysicalMemory));
}
public int BigCalculatationForFirstStep()
{
//第一步运算
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("big calulation");
FirstStepExecuted = true;
return 10;
}
public void NextStep(double memoryUtilization,int firstStepDistance)
{
//下一步运算
if(memoryUtilization
{
注:更多精彩教程请关注山村网页设计教程 栏目,