C#中的函数式编程
在函数式编程中,可以把函数看作数据。函数也可以作为参数,函数还可以返回函数。比如,LINQ就是基于函数式编程的。
两个例子引出函数式编程
语句式编程可能这样写:
string result; if(value > 0) { result = "正数"; } else { result = "负数"; }
而使用函数式表达式,可以简化为:
var result = value > 0 "正数":"负数";
再来看一个过滤和排序的例子:
var i = 0; while(i < list.Count) { if(list[i] % 2 != 0) { list.RemoveAt(i); } else { ++i; } } list.Sort();
函数式编程可以写成如下:
from x in list where x % 2 == 0 orderby x select x;
或
list .where(x => x % 2 == 0) .OrderBy(x => x)
可见,在LINQ中,一个表达式(函数)的返回结果作为令一个表达式(函数)的源,还可以进行多个链式。
封装一个函数式方法
比如读取远程数据。
void Main() { XDocument timeDoc; using(var client = new System.Net.WebClient()) { timeDoc = XDocument.Parse(client.DonwloadString("")); } var ms = Convert.ToInt64(timeDoc.Root.Attribute("time").Value) / 1000; var currentTime = new DateTime(1977,1,1).AddMilliseconds(ms).ToLocalTime(); Console.WriteLine(currentTime); }
对于using部分我们可以提炼出一个方法。
private XDocument GetTime() { using(var client = new System.Net.WebClient()) { return XDocument.Parse(client.DonwloadString("")); } } void Main() { var timeDoc = GetTime(); var ms = Convert.ToInt64(timeDoc.Root.Attribute("time").Value) / 1000; var currentTime = new DateTime(1977,1,1).AddMilliseconds(ms).ToLocalTime(); Console.WriteLine(currentTime); }
但,还不够。以上的GetTime方法只是对WebClient这个实现了IDisposable接口的using语句进行了封装,可不可以对所有实现IDisposable接口的类型的using语句进行封装呢?
public static class MyDisposable { public static TResult Using<TDisposable, TResult>( Func<TDisposable> factory, Func<TDisposable, TResult> map) where TDisposable : IDisposable { using(var disposable = factory()) { return map(disposable); } } } void Main() { var time = MyDisposable .Using( () => new System.Net.WebClient(), client => XDocument.Parse(client.DownloadString("")) ) .Root .Attribute("time") .Value; var ms = Convert.ToInt64(time) / 1000; var currentTime = new DateTime().AddMilliseconds(ms).ToLocalTime(); Console.WriteLine(currentTime); }
在函数式编程中,函数返回的类型基本上另外一个函数方法的源实例。